Posts Tagged ‘RPGLE Date Testing’
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.
I have an input date field on a display that I wanted to initially show as blank because it is used as a filter-by-date value. Blank means nothing was entered by the user so don’t do the filtering. I wanted DDS to force a valid *USA format for input. I also wanted blanks to be a valid input value so the user could clear a previously entered filter-date.
DDS provides a very easy approach to solving this problem without a lot of code in the application. The key to this is the DDS MAPVAL function.
|...+....1....+....2....+....3....+....4....+....5....+....6....+....7....+....8 00030A S1FDATE L DATFMT(*MDY) DATSEP('/') 00040A MAPVAL(('01/01/40' *BLANK))
During an output operation, the field data is compared to each program-value on the MAPVAL keyword in the order in which the program-values are specified. For the first match that is found, the corresponding system-value replaces the current field data. If a match does not exist, the field data does not change.
During an input operation, the field data is compared to each system-value on the MAPVAL keyword in the order in which the system-values are specified. For the first match that is found, the corresponding program-value replaces the current field data. If a match does not exist, the field data remains the same.
Option indicators are not valid for this keyword, although you can use option indicators to condition the field for which it is specified.
On output, if the field data equals ’01/01/40′, the field data is changed to all blanks. On input, if the field data is blank, the field data is changed to ’01/01/40′.
Inside the RPGLE application I defined a few dates to perform format conversion.
D SAVFDATE S D DATFMT(*USA) D DFTFDATE S D DATFMT(*USA) INZ(D'0001-01-01') D CCYYMMDD S D DATFMT(*ISO)
Finally, the logic created to pull it all together.
* A valid *USA date will be returned if entered. A freshly initialized * screen will show the date field as blank, but when it gets to this code * the field has been initialized by RPG to '01/01/0001' which is contained * in DFTFDATE. Comparing SAVFDATE to DFTFDATE is in essence testing for * the fact the user has not entered a valid search date. C SAVFDATE IFNE DFTFDATE C MOVE SAVFDATE CCYYMMDD C MOVE CCYYMMDD SAVFDATEN C RHCTDT IFEQ SAVFDATEN C MOVEL @YES INCLUDE C ELSE C MOVEL @NO INCLUDE C ENDIF C ENDIF