On RPG-LE Development

Postings on RPG-LE and i5/OS

Archive for the ‘RPG Free Date Formatting’ Category

Adding days to a Date using RPGLE

leave a comment »

Problem: you need to add 15 days to a date stored in a manner where its parts are broken into 4 fields.

Here is the data structure used to capture the 4 fields at the time of the I/O (CC,YY,MM,DD). The DS defines fields over them for use by the calculations, specifically NAD_DATE, NAD_DATE_A and NAD_CCYYMMDD.

The Data Structure

 
D NAD_DateDS DS D NAD_DATE 1 8S 0 D NAD_DATE_A 1 8 D CC 1 2S 0 D YY 3 4S 0 D MM 5 6S 0 D DD 7 8S 0 D NAD_CCYYMMDD S D DATFMT(*ISO)

NAD_DATE spanning positions 1 through 8, acts to contain the ccyymmdd components into a single field.
NAD_DATE_A is the character version of NAD_DATE.
NAD_CCYYMMDD is a work-field in *ISO format. NAD_DATE, in ccyymmdd format, is moved to this field.

The Calculations

 
//Move the numeric variant of date in NAD_DATE into NAD_CCYYMMDD of type date //in *ISO format. NAD_CCYYMMDD = %date(NAD_DATE); //Add 15 days to NAD_CCYYMMDD of type date NAD_CCYYMMDD = NAD_CCYYMMDD + %days(15) ; //Convert 2011-07-03 (*ISO format) to a numeric variant of 20110703. The use //of "*iso0" tells the %char function to drop the "-" and leave it in *ISO format. NAD_DATE_A = %char(NAD_CCYYMMDD:*iso0); //Convert 20110703 to decimal value NAD_DATE = %dec( NAD_DATE_A :8:0);

Since the field NAD_DATE is an aggregate variant of the elementary fields in the data structure, the fields CC, YY, MM, DD contain the new sub-component values. If the field names are the same as those of the file, then an update operation will persist the values to the database.

Formatting Current Date and Time using a Data Structure and RPG-ILE Service Programs

leave a comment »

This post is an extension of the post about how to obtain current date and time into a data structure (DS) which serves to format them in various ways. Some of the the DS values can be used in date-calculations while others are suitable for display on page headers and screens without further formatting.

The original post represents an older RPG-IV solution where everything is contained within the application program while this post focuses on a modern approach using RPG-ILE service programming. If you need to see an RPG-IV solution, you can see that post here.

Providing Current Date and Time using RPG-ILE programming techniques

The data structure that was presented in the post referenced above is augmented as shown here. It has been placed into a new source member the primary purpose of which is to copy the Data Structure into all application programs during compile-time using the ‘copy’ directive. The so-called ‘copy member’ also contains the definition of the prototype describing the signature used for the sub-procedure call invoked by the application program.

The copy member source containing the data structure and interface prototype is placed into a source file named QPROTSRC and given the name of DTETIMEDSH.

 
/If Not Defined( DTETIMDSHCopied ) /Define DTETIMDSHCopied /Else /Eof /EndIf D************************************************************************** D* This series of date related values are populated by call to getToday D************************************************************************** D* EX: Value for TimeStamp: '2010-06-30-12.01.54.789000' D TimeStamp S Z D CurrentDate S D DATFMT(*ISO) D CurrentTime S T TIMFMT(*USA) D SysDateDS DS D SysDate 8S 0 D SysTime 6S 0 D TimeStampISODS DS D tsTimeStampISO 14S 0 D tsHHMMSS 6S 0 OVERLAY(tsTimeStampISO:9) D tsHour 2S 0 OVERLAY(tsHHMMSS) D tsMinute 2S 0 OVERLAY(tsHHMMSS:*NEXT) D tsSecond 2S 0 OVERLAY(tsHHMMSS:*NEXT) D tsHHMM 4S 0 OVERLAY(tsHHMMSS:1) D tsYYYYMMDD 8S 0 OVERLAY(tsTimeStampISO:1) D tsYear 4S 0 OVERLAY(tsYYYYMMDD) D tsMonth 2S 0 OVERLAY(tsYYYYMMDD:*NEXT) D tsDay 2S 0 OVERLAY(tsYYYYMMDD:*NEXT) D tsCC 2S 0 OVERLAY(tsYYYYMMDD:1) D tsYY 2S 0 OVERLAY(tsYYYYMMDD:3) D tsYYMMDD 6S 0 OVERLAY(tsYYYYMMDD:3) D tsTimeStampa 1 14A D tsYYYYMMDDa 8A OVERLAY(tsTimeStampISO:1) D tsHHMMSSa 6A OVERLAY(tsTimeStampISO:9) D DateUSADS DS D tsMMDDYYYY 8S 0 D tsMMDDYYYYa 8A OVERLAY(tsMMDDYYYY) D DateNow_ISO S D DATFMT(*ISO) D DateNow_USA S D DATFMT(*USA) D* D************************************************************************** ************************************************************************** * Prototype Interface definition * * Accepts the data structures defined above which will be initialized * with values relative to today's date. * * Input: References to the data structures defined by DteTimDSH * Return: The data structures defined by DteTimDSH with values. * Including DTEIMDSH into the client program is a requirement * so that the returned DSs below will allow the sub fields * to be made available as well ************************************************************************** D getTimestamp Pr D TimeStamp Z D CurrentDate D DATFMT(*ISO) D CurrentTime T TIMFMT(*USA) D SysDate 8S 0 D SysTime 6S 0 D tsHHMMSS 6S 0 D tsYYYYMMDD 8S 0 D tsMMDDYYYY 8S 0 D DateNow_ISO D DATFMT(*ISO) D DateNow_USA D DATFMT(*USA) ************************************************************************** ******** END OF SOURCE ******************************************* **************************************************************************

Shown below is the procedure. It has been placed into the source file QPROCSRC and given the name of DTETIMEDS.

 
H NoMain F************************************************************************** F* P R O G R A M I N F O R M A T I O N S U M M A R Y * F************************************************************************** F* F* PROGRAM - DTETIMDS F* This program populates a data structure related to today's F* Date and Time to be used for time stamp related operations F* F* DATE - 2010/11/10 F* F* F************************************************************************** F* M O D I F I C A T I O N S U M M A R Y * F************************************************************************** F* * F* MODIFICATION HISTORY * F* * F* MODIFIED BY DATE MODIFICATION DESCRIPTION * F* ----------- -------- ----------------------------------------------- * F* 20101110 INITIAL RELEASE F* F* F************************************************************************** /Copy QProtosrc,DteTimDSH D************************************************************************** D* EXTERNAL PROGRAM DATA STRUCTURES D************************************************************************** D* NAME DESCRIPTION D* ---------- ---------------------------------------------------------- D* PGMREF Externally defined Program Status Data Structure D************************************************************************** D PGMREF ESDS 1500 EXTNAME(SYSPGMREF) D TestDate D DATFMT(*USA) P getTimestamp B Export ************************************************************************** * Procedure Interface Public * * Accepts data structure elements defined by DteTimDSH which will be * initialized with values relative to today's date. * * Input: References to the data structures defined by DteTimDSH * Return: The data structures defined by DteTimDSH with values ************************************************************************** D getTimestamp PI D TimeStamp Z D CurrentDate D DATFMT(*ISO) D CurrentTime T TIMFMT(*USA) D SysDate 8S 0 D SysTime 6S 0 D tsHHMMSS 6S 0 D tsYYYYMMDD 8S 0 D tsMMDDYYYY 8S 0 D DateNow_ISO D DATFMT(*ISO) D DateNow_USA D DATFMT(*USA) ************************************************************************** /free exsr getToday; return; //*********************************************************************** //* * //* Capture Today's Date * //* * //*********************************************************************** BEGSR getToday; //Get the current date and time into the TimeStamp field to be used //as the basis for populating SysDateDS sub-fields. SysDateDS is //moved into TimeStampISODS which populates its sub-fields providing //access to the elementary components of date (mm,dd,cc,yy) and time //(hh,mm,ss) // '*ISO-': means convert to *ISO format with dashes as separators, // which means the output of %char() will contain the dashes. // '*ISO0': the 0 means to suppress separators, which is necessary // if you want to convert it to a number. TimeStamp = %timestamp(); SysDate = %Uns( %Char( %Date( TimeStamp ) : *ISO0 ) ); SysTime = %Uns( %Char( %Time( TimeStamp ) : *HMS0 ) ); tsHHMMSS = SysTime; tsYYYYMMDD = SysDate; CurrentDate = %date(TimeStamp); CurrentTime = %time(TimeStamp); DATENOW_ISO = CurrentDate; DATENOW_USA = DATENOW_ISO; tsMMDDYYYY = %Uns( %Char( %Date( TimeStamp ) : *USA0 ) ); ENDSR; /end-free P E /EJECT ************************************************************************** ******** END OF SOURCE ******************************************* **************************************************************************

Notable parts of the procedure are the “/copy” statement which pulls in the prototype definition and the data structure, the externally defined program status data structure (replace with your own), the procedure definition which establishes the name of the procedure as “getTimestamp”, its interface which defines the expected parameters to be passed to it by the client which calls “getTimestamp” and the mainline logic which then calls the internally defined subroutine called “getToday” which does all the work.

To use the procedure, the client program should include the following elements. First, there is the /copy statement used to pull in the source member for the prototype named DTETIMDSH.

 
D************************************************************************** D* D* NAME DESCRIPTION D* ---------- ---------------------------------------------------------- D* DteTimDSH Date-Time Data Structure. Populated with this proc-call: D* getTimestamp(TimeStamp:CurrentDate:CurrentTime:SysDate: D* SysTime:tsHHMMSS:tsYYYYMMDD:tsMMDDYYYY:DateNow_ISO: D* DateNow_USA); D* D* D* D* D************************************************************************** D/Copy LibraryName/QProtosrc,DteTimDSH D* D**************************************************************************

In the startup routines, represented here by a subroutine called “startUp”, the client program calls the service program’s “getTimestamp” sub-procedure.

 
/EJECT //*********************************************************************** //* * //* Start Up Processing - Since this program may be called from other * //* programs and can return to the caller without setting on LR, * //* process the *ENTRY parms and other processing to be performed on * //* each call here. * //* * //* List of tasks to be performed here are: * //* o Processing of *ENTRY parameters * //* o Obtaining today's date in multiple formats * //* * //*********************************************************************** BEGSR startUp; //************************************************** // Populate the Time Stamp related data structures //************************************************** getTimestamp(TimeStamp:CurrentDate:CurrentTime:SysDate:SysTime: tsHHMMSS:tsYYYYMMDD:tsMMDDYYYY:DateNow_ISO:DateNow_USA); ENDSR;

After the call completes, the DS field values will contain the current date in several different formats and in some cases, the component parts of month, day and year as shown below.

CURRENTDATE 		= 2010-11-17	

CURRENTTIME 		= 09:53 AM
	
DATENOW_ISO 		= 2010-11-17	

DATENOW_USA 		= 11/17/2010	

DATEUSADS	
	TSMMDDYYYYA 	= 11172010	
	TSMMDDYYYY 	= 11172010. 	

SYSDATEDS	
	SYSDATE		= 20101117. 	
	SYSTIME 	= 095313. 	

TIMESTAMP 		= 2010-11-17-09.53.13.946000	

TIMESTAMPISODS	
	TSYYYYMMDDA 	= 20101117	
	TSYYYYMMDD 	= 20101117. 	
	TSTIMESTAMPA 	= 20101117095313	
	TSTIMESTAMPISO 	= 20101117095313. 	
	TSYEAR 		= 2010. 	
	TSCC 		= 20. 	
	TSYY 		= 10. 	
	TSYYMMDD 	= 101117. 	
	TSMONTH 	= 11. 	
	TSDAY 		= 17. 	
	TSHHMMSSA 	= 095313	
	TSHHMMSS 	= 095313. 	
	TSHHMM 		= 0953. 	
	TSHOUR 		= 09. 	
	TSMINUTE 	= 53. 	
	TSSECOND 	= 13. 	

Date Formatting using RPG-ILE’s Built-in Functions

with 2 comments

The following date formatting functions reference the stand-alone fields defined below:

H option(*nodebugio)                                                   
                                                                      
D @charA          S              8    inz('04/12/01')                  
D @charB          S             10    inz('12/02/2004')                
D @charC          S              8    inz('12/03/04')                  
                                                                      
D @dateA          S               d   inz(D'2004-12-04')               
                                                                      
D @numA           S              6  0 inz(041205)                      
D @numB           S              7  0 inz(1041206)                     
D @numC           S              8  0 inz(20041207)                    
D @numD           S              6  0 inz(120804)                      
D @numE           S              8  0 inz(12092004)         

/free // character to character... @charB = %char(%date(@charA:*ymd/):*usa/); // 'yy/mm/dd' to 'mm/dd/ccyy' @charC = %char(%date(@charA:*ymd/):*mdy/); // 'yy/mm/dd' to 'mm/dd/yy' @charA = %char(%date(@charB:*usa/):*ymd/); // 'mm/dd/ccyy' to 'yy/mm/dd' @charC = %char(%date(@charB:*usa/):*mdy/); // 'mm/dd/ccyy' to 'mm/dd/yy' @charA = %char(%date(@charC:*mdy/):*ymd/); // 'mm/dd/yy' to 'yy/mm/dd' @charB = %char(%date(@charC:*mdy/):*usa/); // 'mm/dd/yy' to 'mm/dd/ccyy' // character to date... @dateA = %date(@charA:*ymd/); // 'yy/mm/dd' to D'ccyy-mm-dd' @dateA = %date(@charB:*usa/); // 'mm/dd/ccyy' to D'ccyy-mm-dd' @dateA = %date(@charC:*mdy/); // 'mm/dd/yy' to D'ccyy-mm-dd' // character to numeric... @numA = %dec(%char(%date(@charA:*ymd/):*ymd0):6:0); // 'yy/mm/dd' to yymmdd @numB = %dec(%char(%date(@charA:*ymd/):*cymd0):7:0); // 'yy/mm/dd' to cyymmdd @numC = %dec(%char(%date(@charA:*ymd/):*iso0):7:0); // 'yy/mm/dd' to ccyymmdd @numD = %dec(%char(%date(@charA:*ymd/):*mdy0):7:0); // 'yy/mm/dd' to mmddyy @numE = %dec(%char(%date(@charA:*ymd/):*usa0):7:0); // 'yy/mm/dd' to mmddyyyy @numA = %dec(%char(%date(@charB:*usa/):*ymd0):6:0); // 'mm/dd/ccyy' to yymmdd @numB = %dec(%char(%date(@charB:*usa/):*cymd0):7:0); // 'mm/dd/ccyy' to cyymmdd @numC = %dec(%char(%date(@charB:*usa/):*iso0):7:0); // 'mm/dd/ccyy' to ccyymmdd @numD = %dec(%char(%date(@charB:*usa/):*mdy0):7:0); // 'mm/dd/ccyy' to mmddyy @numE = %dec(%char(%date(@charB:*usa/):*usa0):7:0); // 'mm/dd/ccyy' to mmddyyyy @numA = %dec(%char(%date(@charC:*mdy/):*ymd0):6:0); // 'mm/dd/yy' to yymmdd @numB = %dec(%char(%date(@charC:*mdy/):*cymd0):7:0); // 'mm/dd/yy' to cyymmdd @numC = %dec(%char(%date(@charC:*mdy/):*iso0):7:0); // 'mm/dd/yy' to ccyymmdd @numD = %dec(%char(%date(@charC:*mdy/):*mdy0):7:0); // 'mm/dd/yy' to mmddyy @numE = %dec(%char(%date(@charC:*mdy/):*usa0):7:0); // 'mm/dd/yy' to mmddyyyy // date to character... @charA = %char(@dateA:*ymd/); // D'ccyy-mm-dd' to 'yy/mm/dd' @charB = %char(@dateA:*usa/); // D'ccyy-mm-dd' to 'mm/dd/ccyy' @charC = %char(@dateA:*mdy/); // D'ccyy-mm-dd' to 'mm/dd/yy' // date to numeric... @numA = %dec(%char(@dateA:*ymd/):6:0); // D'ccyy-mm-dd' to yymmdd @numB = %dec(%char(@dateA:*cymd/):7:0); // D'ccyy-mm-dd' to cyymmdd @numC = %dec(%char(@dateA:*iso-):8:0); // D'ccyy-mm-dd' to ccyymmdd @numD = %dec(%char(@dateA:*mdy/):6:0); // D'ccyy-mm-dd' to mmddyy @numE = %dec(%char(@dateA:*usa/):8:0); // D'ccyy-mm-dd' to mmddccyy // numeric to character... @charA = %char(%date(@numA:*ymd):*ymd/); // yymmdd to 'yy/mm/dd' @charB = %char(%date(@numA:*ymd):*usa/); // yymmdd to 'mm/dd/ccyy' @charC = %char(%date(@numA:*ymd):*mdy/); // yymmdd to 'mm/dd/yy' @charA = %char(%date(@numB:*cymd):*ymd/); // cyymmdd to 'yy/mm/dd' @charB = %char(%date(@numB:*cymd):*usa/); // cyymmdd to 'mm/dd/ccyy' @charC = %char(%date(@numB:*cymd):*mdy/); // cyymmdd to 'mm/dd/yy' @charA = %char(%date(@numC:*iso):*ymd/); // D'ccyy-mm-dd' to 'yy/mm/dd' @charB = %char(%date(@numC:*iso):*usa/); // D'ccyy-mm-dd' to 'mm/dd/ccyy' @charC = %char(%date(@numC:*iso):*mdy/); // D'ccyy-mm-dd' to 'mm/dd/yy' @charA = %char(%date(@numD:*mdy):*ymd/); // mmddyy to 'yy/mm/dd' @charB = %char(%date(@numD:*mdy):*usa/); // mmddyy to 'mm/dd/ccyy' @charC = %char(%date(@numD:*mdy):*mdy/); // mmddyy to 'mm/dd/yy' @charA = %char(%date(@numE:*usa):*ymd/); // mmddccyy to 'yy/mm/dd' @charB = %char(%date(@numE:*usa):*usa/); // mmddccyy to 'mm/dd/ccyy' @charC = %char(%date(@numE:*usa):*mdy/); // mmddccyy to 'mm/dd/yy' // numeric to date... @dateA = %date(@numA:*ymd); // yymmdd to D'ccyy-mm-dd' @dateA = %date(@numB:*cymd); // cyymmdd to D'ccyy-mm-dd' @dateA = %date(@numC:*iso); // ccyymmdd' to D'ccyy-mm-dd' @dateA = %date(@numD:*mdy); // mmddyy to D'ccyy-mm-dd' @dateA = %date(@numE:*usa); // mmddccyy to D'ccyy-mm-dd' // numeric to numeric... @numB = %dec(%char(%date(@numA:*ymd):*cymd0):7:0); // yymmdd to cyymmdd @numC = %dec(%char(%date(@numA:*ymd):*iso0):8:0); // yymmdd to ccyymmdd @numD = %dec(%char(%date(@numA:*ymd):*mdy0):6:0); // yymmdd to mmddyy @numE = %dec(%char(%date(@numA:*ymd):*usa0):8:0); // yymmdd to mmddccyy @numA = %dec(%char(%date(@numB:*cymd):*ymd0):6:0); // cyymmdd to yymmdd @numC = %dec(%char(%date(@numB:*cymd):*iso0):8:0); // cyymmdd to ccyymmdd @numD = %dec(%char(%date(@numB:*cymd):*mdy0):6:0); // cyymmdd to mmddyy @numE = %dec(%char(%date(@numB:*cymd):*usa0):8:0); // cyymmdd to mmddccyy @numA = %dec(%char(%date(@numC:*iso):*ymd0):6:0); // ccyymmdd to yymmdd @numB = %dec(%char(%date(@numC:*iso):*cymd0):7:0); // ccyymmdd to cyymmdd @numD = %dec(%char(%date(@numC:*iso):*mdy0):6:0); // ccyymmdd to mmddyy @numE = %dec(%char(%date(@numC:*iso):*usa0):8:0); // ccyymmdd to mmddccyy @numA = %dec(%char(%date(@numD:*mdy):*ymd0):6:0); // mmddyy to yymmdd @numB = %dec(%char(%date(@numD:*mdy):*cymd0):7:0); // mmddyy to cyymmdd @numC = %dec(%char(%date(@numD:*mdy):*iso0):8:0); // mmddyy to ccyymmdd @numE = %dec(%char(%date(@numD:*mdy):*usa0):8:0); // mmddyy to mmddccyy @numA = %dec(%char(%date(@numE:*usa):*ymd0):6:0); // mmddccyy to yymmdd @numB = %dec(%char(%date(@numE:*usa):*cymd0):7:0); // mmddccyy to cyymmdd @numC = %dec(%char(%date(@numE:*usa):*iso0):8:0); // mmddccyy to ccyymmdd @numD = %dec(%char(%date(@numE:*usa):*mdy0):6:0); // mmddccyy to mmddyy

Written by Ben

2010/12/02 at 2:19 pm

Formatting Current Date and Time using a Data Structure and RPG-IV

leave a comment »

It’s rare to write a program and not need some form of date and time. Often you need both. With a carefully crafted Data Structure, extracting the date and time becomes relatively painless. The bonus with this approach is that you get today’s date and time formatted in various ways. This proves useful for comparison operations, aging scenarios, and report page and screen headers.


Using An RPG-IV Approach

This approach uses RPG-IV based code and a basic data structure.

Shown below is a data structure defining a date/time format. Under TimeStamp the data has been subdivided where values for the whole timestamp can be obtained (tsTimeStamp) in addition to acquiring the following values.

Hours, minutes and second in field tsHHMMSS
Century, year, month and day in field tsYYYYMMDD [*ISO format]
Month, day, century and year in field tsMMDDYYYY [*USA format]

     D TimeStamp       DS
     D   tsTimeStamp                 14S 0
     D   tsHHMMSS                     6S 0 OVERLAY(tsTimeStamp:1)
     D     tsHour                     2S 0 OVERLAY(tsHHMMSS)
     D     tsMinute                   2S 0 OVERLAY(tsHHMMSS:*NEXT)
     D     tsSecond                   2S 0 OVERLAY(tsHHMMSS:*NEXT)
     D   tsYYYYMMDD                   8S 0 OVERLAY(tsTimeStamp:7)
     D     tsYear                     4S 0 OVERLAY(tsYYYYMMDD)
     D     tsMonth                    2S 0 OVERLAY(tsYYYYMMDD:*NEXT)
     D     tsDay                      2S 0 OVERLAY(tsYYYYMMDD:*NEXT)
     D   tsMMDDYYYY                   8S 0 OVERLAY(tsTimeStamp:7)
     D     tsMM                       2S 0 OVERLAY(tsMMDDYYYY)
     D     tsDD                       2S 0 OVERLAY(tsMMDDYYYY:*NEXT)
     D     tsYYYY                     4S 0 OVERLAY(tsMMDDYYYY:*NEXT)

     D DateNow_ISO     S               D   DATFMT(*ISO)
     D DateNow_USA     S               D   DATFMT(*USA)
     D BirthDate       S               D   DATFMT(*ISO)

Also shown are some stand-alone fields to contain the current date and time in *ISO and *USA format in addition to a date defining an arbitrary birthdate.

To populate the data structure with the current date and time, the following code is used.

C                   TIME                    tsTimeStamp

Although the data structure contains a properly formatted date and time, the problem is that we don’t know which format was used by the system to populate the data structure. System date formats can be established by third-party software packages or by setting the appropriate i5/OS system values. The next set of code shown below makes that determination. The code is biased to *ISO format.

      * What format is the timestamp in?  We want YYYYMMDD
     C     *ISO          TEST(D)                 tsYYYYMMDD             99
     C     *IN99         IFEQ      *OFF
     C                   MOVE      tsYYYYMMDD    DATENOW_ISO
      *
      * Date is not in *ISO format; check for *USA
     C                   ELSE
     C     *USA          TEST(D)                 tsMMDDYYYY             99
     C     *IN99         IFEQ      *OFF
     C                   MOVE      tsYYYYMMDD    DATENOW_USA
     C                   MOVE      DATENOW_USA   DATENOW_ISO
     C                   ENDIF
      *
     C                   ENDIF

With the system date obtained in an *ISO format, calculations like the one below which determine the number of years elapsed from a given date can be safely made without the system issuing an error.

     C                   MOVE      RDDOB         BIRTHDATE
     C     DATENOW_ISO   SUBDUR    BIRTHDATE     S2AGE:*Y


Redesigning the Solution Using an RPG-ILE Service Program


To see how this design is converted to use a more modern approach which uses a RPG-ILE service program, click here.

Written by Ben

2010/02/03 at 12:32 am

Follow

Get every new post delivered to your Inbox.