ILE RPG epoch functions

When working with the Integrated File System (IFS), it is often useful to convert file dates into real timestamp values. IFS file date/time attributes are stored in *NIX epoch format. The *NIX epoch is the number of seconds since midnight, 1 January 1970.

I had some projects working with Scott Klement’s FTPAPI, where I need to do date comparisons based on a file’s modified date. Here are the Wikipedia entries for epoch and UNIX time.

CvtEpochTS() procedure

Converts a *NIX epoch to an ILE RPG timestamp.



      // Convert Unix timestamp to OS/400 timestamp.
     d CvtEpochTS      pr              z
     d  inEpochSecs                  10i 0 const
     d  inAdjustUTC                    n   const options(*nopass)

      // -----------------------------------------------------------------------
      // CvtEpochTS
      // ----------
      // Helper routine to convert UNIX-type epoch values (typically the number
      // of seconds from midnight, Jan 1, 1970) to an OS/400 timestamp value.
      // The UNIX-type epoch value is considered the "timestamp" value to the
      // UNIX world.
      //
      // INPUTS
      // inEpochSecs int
      //      The UNIX timestamp, in UNIX epoch format (number of seconds since
      //      midnight, Jan 1, 1970.
      // [nAdjustUTC] bool
      //      Optional parameter.
      //      Determine whether the time should be adjusted by the UTC offset.
      //      *true - adjust for UTC offset (default value)
      //      false - do not adjust for UTC offset
      //
      // OUTPUTS
      // OS400Timestamp char[26]
      //      Equivalent OS/400 timestamp value.

     p CvtEpochTS      b

     d CvtEpochTS      pi              z
     d  inEpochSecs                  10i 0 const
     d  inAdjustUTC                    n   const options(*nopass)

      // Constants.
     d EPOCHSTART      s               z   inz(z'1970-01-01-00.00.00.000000')

      // Variables.
     d returnts        s               z   inz(z'0001-01-01-00.00.00.000000')
     d utcoffhours     s             10i 0 inz
     d utcoffmins      s             10i 0 inz
     d utcoffsecs      s              8f   inz
     d utcoffset       s             10i 0 inz
     d workAdjustUTC   s                   inz like(inAdjustUTC)

     d GetUTCOffset    pr                  extproc('CEEUTCO')
     d  offsethours                  10i 0
     d  offsetminutes                10i 0
     d  offsetseconds                 8f
     d  feedback                     12a   options(*nopass)

      /free

         if %parms() < 2;
              workAdjustUTC = *on;
         else;
              workAdjustUTC = inAdjustUTC;
         endif;
         returnts = EPOCHSTART + %seconds(inEpochSecs);
         if workAdjustUTC;
              callp(e) GetUTCOffset(utcoffhours:utcoffmins:utcoffsecs);
              utcoffset = utcoffsecs;
              returnts += %seconds(utcoffset);
         endif;
         return returnts;

      /end-free

     p CvtEpochTS      e


CvtTsEpoch() procedure

Converts an ILE RPG timestamp to a *NIX epoch.



      // Convert OS/400 timestamp to Unix timestamp.
     d CvtTSEpoch      pr            10i 0
     d  inTS                           z   const
     d  inAdjustUTC                    n   const options(*nopass)

      // -----------------------------------------------------------------------
      // CvtTSEpoch
      // ----------
      // Helper routine to convert OS/400 timestamp to UNIX-type epoch.
      // KNOWN LIMITATIONS:
      // * Unknown results if used before 1/1/1970.
      //
      // INPUTS
      // inOS400Timestamp char[26]
      //      OS/400 timestamp value.
      // [inAdjustUTC] bool
      //      Optional parameter.
      //      Determine whether the time should be adjusted by the UTC offset.
      //      *true - adjust for UTC offset (default value)
      //      false - do not adjust for UTC offset
      //
      // OUTPUTS
      // outEpochSecs int
      //      The UNIX timestamp, in UNIX epoch format (number of seconds since
      //      midnight, Jan 1, 1970.

     p CvtTSEpoch      b

     d CvtTSEpoch      pi            10i 0
     d  inOS400Timestamp...
     d                                 z   const
     d  inAdjustUTC                    n   const options(*nopass)

      // Constants.
     d EPOCHSTART      s               z   inz(z'1970-01-01-00.00.00.000000')

      // Variables.
     d returnepoch     s             10i 0 inz
     d utcoffhours     s             10i 0 inz
     d utcoffmins      s             10i 0 inz
     d utcoffsecs      s              8f   inz
     d utcoffset       s             10i 0 inz
     d workAdjustUTC   s                   inz like(inAdjustUTC)

     d GetUTCOffset    pr                  extproc('CEEUTCO')
     d  offsethours                  10i 0
     d  offsetminutes                10i 0
     d  offsetseconds                 8f
     d  feedback                     12a   options(*nopass)

      /free

         if %parms() < 2;
              workAdjustUTC = *on;
         else;
              workAdjustUTC = inAdjustUTC;
         endif;
         returnepoch = %diff( inOS400Timestamp : EPOCHSTART : *seconds );
         if workAdjustUTC;
              callp(e) GetUTCOffset(utcoffhours:utcoffmins:utcoffsecs);
              utcoffset = utcoffsecs;
              returnepoch -= utcoffset;
         endif;
         return returnepoch;

      /end-free

     p CvtTSEpoch      e


Example usage

Sample usage of both procedures.



     h dftactgrp(*no) actgrp('QILE')

      /include source,prototypes
      // ... or where ever you put the epoch functions

     d myts            s               z   inz(z'1978-09-02-18.52.54.000000')
     d mytsepoch       s             10i 0 inz
     d myepoch         s             10i 0 inz(273628374)
     d myepochts       s               z   inz

      /free

         myepochts = CvtEpochTS( myepoch : *on );
         mytsepoch = CvtTSEpoch( myts : *on );

         *inlr = *on;
         return;

      /end-free

      /include source,procedures
      // ... or where ever you put the epoch functions