RPG Date Idiosyncrasies

RPG date logic is not quite as straight forward as it may seem. For example, starting with the date 05/31/2004 and adding a month cannot produce a date of 6/31/2004, since the date is not valid. The result in DATEE6 is 06/30/2004, the valid month ending date. Subtracting a month does not return to the original starting date of 05/31/2004 instead, the date result in DATE65 is 05/30/2004.

     D $eomdate        S               D   inz(d'2004-05-31')
     D $wrkdte         S               D
     D DateE5          S              8  0
     D DateE6          S              8  0
     D Date65          S              8  0
     D Days30          S              8  0
     D Day_30          S              8  0
     D DaysUSA         S              8  0   
     D wrk5            S              5      
     D wrk8            S              8      


         DateE5 = %dec(%char($eomdate:*iso0):8:0);
         $wrkdte = $eomdate + %months(1);
         DateE6 = %dec(%char($wrkdte:*iso0):8:0);
         DATE65  = %dec(%char($wrkdte - %months(1):*iso0):8:0);

        // Adding 30-days to the date value produces the date value of 06/30/2004.
        // Subtracting 30-days from the derived date however, retuns to the
        // original starting point of 05/31/2004.

         $wrkdte = $eomdate + %days(30);
         Days30 = %dec(%char($wrkdte:*iso0):8:0);
         Day_30 = %dec(%char($wrkdte - %days(30):*iso0):8:0);

       // Converting numeric values to character present another type of
       // problem. using the %CHAR BIF tends to strip the leading zero. 
       // If the leading zero is required for display or print, use the 
       // EVALR to right adjust the value, then %XLATE to convert the   
       // X'40' to X'F0'.                                               
         DaysUSA = %dec(%char($wrkdte:*usa0):8:0);                      
         evalr wrk8 = %char(DaysUSA);                                   
         wrk8 = %xlate(' ':'0':wrk8);                                   
         wrk5 = %subst(wrk8:1:2) + ':' + %subst(wrk8:3:2);              
         *inlr = *on;


     D                 DS
     D DiffDate                       8  0
     D   DiffYears                    4  0 overlay(DiffDate)
     D   DiffMonths                   2  0 overlay(DiffDate: *Next)
     D   DiffDays                     2  0 overlay(DiffDate: *Next)

     D NbrofDays       S              9p 0
     D NumDays         S              9p 0
     D weekDay         S             10i 0
     D weekDay7        S             10i 0
     D dayOfWeek       S             10i 0
     D dayOfWeek2      S             10i 0
     D dayOfYear       S             10i 0
     D DateChar        S             10A
     D DayName         S             12A
     D Date1           S               D   inz(D'2004-07-01')
     D Date2           S               D   inz(*SYS)
     D DtTmStamp       S               z   inz(*SYS)

       // Using Subtract Duration (SUBDUR) RPG makes it fairly simpe
       // to calculate the difference between two dates in years, months

     C     Date1         subdur    Date2         NbrofDays:*D
     C                   eval      numDays    = %Diff(Date1: Date2: *Days)
     C                   Eval          date1 = %date('2015-11-08':*ISO)

       // Embedded SQL can be used to calculate the difference by populating 
       // a data structure with the results--with the difference showing 
       // as the number of years, months, and days between the two dates.
     c/EXEC SQL
     C+    set :DiffDate  = :Date1 - :Date2

     c/EXEC SQL
     C+    set :DateChar  = TO_CHAR(:DtTmStamp, 'MM-DD-YYYY')

     c/EXEC SQL
     C+    set :DayName  = dayName(:date2)

       // Both RPG and SQL have a simple method of determining the day 
       // of the week. In SQL you may simple use the DAYOFWEEK function.
       // In RPG set the date to an initial value of d'0001-01-01' and 
       // using the remainder BIF, the day of the week, 1,2,3,4 etc. will
       // be calculated.


          EXEC SQL set :dayOfWeek = dayOfWeek_ISO(:date2);
          EXEC SQL set :dayOfWeek2 = dayOfWeek(:date2);
          EXEC SQL set :dayOfYear = dayOfYear(:date2);

        // To return a number based on 1=Monday, use 01 for day.
        // for 1=Sunday, use 07 for day.

          WeekDay = %rem(%diff(Date2:d'0001-01-01':*d) : 7) + 1   ;
          WeekDay7= %rem(%diff(Date2:d'0001-01-07':*d) : 7) + 1   ;