RPG IV Legacy Dates Cheat Sheet

RPG
Typography
  • Smaller Small Medium Big Bigger
  • Default Helvetica Segoe Georgia Times

Still stuck with legacy date and time fields in your database and programs? Let RPG IV do the heavy lifting for you.

 

In V5R3, date-handling is superb and calculations are straightforward. Fine, you say, but what about all those pesky character or numeric fields we still have to fight with from designs that originated before the date- and time-field data types were available? Those fields might have two- or four-digit years and might be in YMD order or MDY order or, outside the U.S. , even DMY order. What about them?

 

No sweat. RPG handles these legacy fields easily and concisely, but based on code I've seen recently, not everyone knows how to do it.

 

I'm surprised that some developers still write code that uses data structures or sub-stringing or concatenation to manipulate dates—not only in converted RPG III code, but also in new RPG IV development. Much of this code deals with creating legacy date and time fields used to timestamp database records, though it isn't restricted to this, because you often want to add or subtract from one of these stored dates. In many cases, the developer has some reusable, tried-and-tested code snippets. While I applaud code reuse, it wouldn't hurt to upgrade the code, because RPG IV date-handling makes the code shorter and easier to understand.

Some Bad Examples

Following are three examples of code that I came across recently. I found each as shown; all I've done is add standalone fields in place of database fields. See if you find any obvious errors.

 

This is example 1, from a developer who has been writing code for at least 10 years:

     D t_audit_date    s              8p 0

     D t_audit_time    s              6p 0

     D #TimeDate       DS

     D  #Time                  1      6  0

     D  #Date                  7     14  0

     D #CYMD           S               D   DATFMT(*ISO)

     C                   time                    TimeStamp        14 0

     C                   move      TimeStamp     #TimeDate

     C     * USA           move      #Date         #CYMD

     C                   move      #cymd         wrkdate           8 0

     C                   move      wrkdate       t_audit_date

     C                   move      #time         t_audit_time

 

This is example 2. Similar code also turned up in several programs this developer wrote.

     D Todays_Date_C   DS             8

     D  Todays_Date                   8  0 Overlay(Todays_Date_C)

     D Curr_Date       s               D   inz(*sys)

      /free

             Todays_Date_C =  %subst(%Char(Curr_Date):1:4) +

                              %subst(%Char(Curr_Date):6:2) +

                              %subst(%Char(Curr_Date):9:2);

 

This is example 3. An experienced developer from a large contracting company wrote this about three years ago.

     h DATEDIT(*YMD)

     D HMDATE          S              8A

     D HMTIME          S              6S 0

     c                   move      *Date         HMDATE

     c                   TIME                    HMTIME

 

Now, what's your opinion of the above code? Do you see any problems? 

Better Examples

While I labeled them as bad examples, two of the routines work well, and the third works most of the time. But the code can be better.

 

Bad example 1 works. This is a snippet of debugged code that the developer uses routinely. The main problem is the wordiness and the obfuscation caused by using the data structure. Data structures have their place, but when used like this, you have to look at two places in the program to see what's going on. Consider this shorter code, which produces the same result without using a data structure.

     D t_audit_date    s              8p 0

     D t_audit_time    s              6p 0

     D TimeStamp       s               z

      /FREE

        TimeStamp = %timestamp();

        t_audit_date = %dec(%date(Timestamp):*ISO);

        t_audit_time = %dec(%time(Timestamp):*HMS);

 

Bad example 2 also works, and again, the only problem is the wordiness. This much shorter piece of code produces the same results.

     D Todays_Date     s              8  0

     D Curr_Date       s               D   inz(*sys)

      /free

             Todays_Date = %dec(Curr_Date:*ISO);

 

Bad example 3 really is bad, though it works most of the time. (For reference, check if your boss thinks accuracy 99 percent of the time is acceptable.) I've seen this combination of a reserved word and the TIME opcode in way too many programs. In RPG IV, the reserved words UDATE, *DATE, UMONTH, *MONTH, UYEAR, *YEAR, UDAY, and *DAY all refer to the date the job started to run. This job date does not change. The TIME opcode, on the other hand, comes from the system clock that is constantly changing. If the job runs past midnight, such date and time combinations will be incorrect, and it will look like the later transactions occurred before the earlier ones.

 

It makes little sense to combine a static date and a variable time to timestamp a record unless you can guarantee that the job will never run past midnight. Why take the risk? This is the correct (and just as easy) way to timestamp a record with legacy fields:

     D HMDATE          S              8A

     D HMTIME          S              6S 0

     D TS              S               Z

      *=======================================================

      /free

       TS = %timestamp();

       HMDATE = %char(%date(TS):*ISO0);

       HMTIME = %dec(%time(TS):*HMS);

The Cheat Sheet

OK, here's the cheat sheet—short on theory, long on examples. It is in the form of an RPG IV program, with the variable names constructed to let you intuitively know what they contain. CC, for example, represents the century, the first two digits, of a year. YY is the last two digits of a year, MM is the month of a year, and DD is the day of a year. C by itself means 0 for 19 and 1 for 20. At the end of the variable name, _n means it is a numeric field and _c means it is a character field. So CCYYMMDD_n is a numeric field that might contain 20071231.

 

The first section is for creating legacy fields in a variety of formats. The second section is for converting legacy fields to native data types so that you can easily do calculations on them.

 

      * Legacy Date and Time Handling Cheat Sheet

     D TS              s               z

     D Date            s               d

     D CCYYMMDD_n      s              8  0

     D YYMMDD_n        s              6  0

     D CYYMMDD_n       s              7  0

     D MMDDYY_n        s              6  0

     D

     D CCYYMMDD_c      s              8

     D YYMMDD_c        s              6

     D CYYMMDD_c       s              7

     D MMDDYY_c        s              6

     D HHMMSS_n        s              6  

     D HHMMSS_c        s              6

      /free

       //=== Legacy Date & Time Stamps - from System Clock ===

       TS = %timestamp();

           //--- Set Numeric Legacy Date Fields ---

           CCYYMMDD_n = %dec(%date(TS): *ISO);

           YYMMDD_n = %dec(%date(TS): *YMD);

           CYYMMDD_n = %dec(%date(TS): *CYMD);

           MMDDYY_n = %dec(%date(TS): *MDY);

           //--- Set Character Legacy Date Fields ---

           CCYYMMDD_c = %char(%date(TS): *ISO0);

           YYMMDD_c = %char(%date(TS): *YMD0);

           CYYMMDD_c = %char(%date(TS): *CYMD0);

           MMDDYY_c = %char(%date(TS): *MDY0);

           //--- Set Legacy Time Fields ---

           HHMMSS_n = %dec(%time(TS): *HMS);

           HHMMSS_c = %char(%time(TS): *HMS0);

       //=== Legacy Date Stamp from Job Date ===

       CCYYMMDD_n = %dec(%date(*DATE): *ISO);

       CCYYMMDD_c = %char(%date(*DATE): *ISO0);

       //=== Converting Legacy Dates to True Dates ===

           //--- True date from numeric fields ---

           Date = %date(122507: *MDY);

           Date = %date(251207: *DMY);

           Date = %date(071225: *YMD);

           Date = %date(12252007: * USA );

           Date = %date(25122007: *EUR);

           Date = %date(20071225: *ISO);

           //--- True date from character fields, no separators ---

           Date = %date('122507': *MDY0);

           Date = %date('251207': *DMY0);

           Date = %date('071225': *YMD0);

           Date = %date('12252007': *USA0);

           Date = %date('25122007': *EUR0);

           Date = %date('20071225': *ISO0);

           //--- True date from character fields with separators ---

           Date = %date('12/25/07': *MDY);

           Date = %date('25/12/07': *DMY);

           Date = %date('07/12/25': *YMD);

           Date = %date('12/25/2007': * USA );

           Date = %date('25.12.2007': *EUR);

           Date = %date('2007-12-25': *ISO);

 

See how easy it is? There is no longer any need for data structures, sub-stringing, or concatenation to create legacy dates and times. Nor is any trickery needed to convert a legacy field to a native data type. Just print this code and pin it on your wall as a reference. And be sure to share it with your coworkers who don't read MC Press Online so they know what they are missing.

Sam Lennon

Sam Lennon is an analyst, developer, consultant and IBM i geek. He started his programming career in 360 assembly language on IBM mainframes, but moved to the AS400 platform in 1991 and has been an AS400/iSeries/i5/IBM i advocate ever since.

BLOG COMMENTS POWERED BY DISQUS

LATEST COMMENTS

Support MC Press Online

$

Book Reviews

Resource Center

  •  

  • LANSA Business users want new applications now. Market and regulatory pressures require faster application updates and delivery into production. Your IBM i developers may be approaching retirement, and you see no sure way to fill their positions with experienced developers. In addition, you may be caught between maintaining your existing applications and the uncertainty of moving to something new.

  • The MC Resource Centers bring you the widest selection of white papers, trial software, and on-demand webcasts for you to choose from. >> Review the list of White Papers, Trial Software or On-Demand Webcast at the MC Press Resource Center. >> Add the items to yru Cart and complet he checkout process and submit

  • SB Profound WC 5536Join us for this hour-long webcast that will explore:

  • Fortra IT managers hoping to find new IBM i talent are discovering that the pool of experienced RPG programmers and operators or administrators with intimate knowledge of the operating system and the applications that run on it is small. This begs the question: How will you manage the platform that supports such a big part of your business? This guide offers strategies and software suggestions to help you plan IT staffing and resources and smooth the transition after your AS/400 talent retires. Read on to learn: