IBM Support

The Difference Between the TIME OpCode in RPG and the MI Instruction MATTOD

Troubleshooting


Problem

In RPG, the TIME operation and the %TIMESTAMP built-in function access the system time of day and the system date at any time during program processing. The time portion is returned with an approximation of +/- 1 millisecond; therefore, the microsecond digits in the resulting timestamp are always 0. The maximum system clock resolution attainable on IBM i servers is +/- 8 microseconds.

Resolving The Problem

This article has two examples showing how to obtain a timestamp with a precision greater than millisecond precision. An ILE RPG example shows how to call MATTOD to obtain a system 8-byte timestamp and then how to call QWCCVTDT to convert that to an RPG-style timestamp in YYYY-MM-DD-hh.mm.ss.uuuuuu format. An ILE C/C++ example shows how to call MATTOD and then how to call Qp0zCvtToTimeval to obtain a "timeval" value with seconds and microseconds.
Note:  On more powerful IBM i models, the MATTOD instruction can run fast enough that multiple invocations of it completes within the same 8-microsecond window, therefore, returning identical timestamps.
Example in ILE RPG IV programming language.
           /if defined(*CRTBNDRPG)
              // Run in a *NEW activation group so the printf
              // output will print immediately when the program ends
              ctl-opt actgrp(*new);
           /endif
           // Define the array to store 100 timestamps.
           dcl-c arraysize 100;
           dcl-s mi_time_vals char(8) dim(arraysize);
           // Prototype for mattod
           dcl-pr mattod extproc(*dclcase);
              mi_time char(8);
           end-pr;
           dcl-s i int(10);
           dcl-s ts timestamp;
           // Call MATTOD until the array is filled.
           for i = 1 to arraysize;
              mattod (mi_time_vals(i));
           endfor;
           // Convert each element to a regular timestamp and display
           for i = 1 to arraysize;
              ts = cvtTimestamp (mi_time_vals(i));
              print (%char(ts));
           endfor;
           return;
           dcl-proc cvtTimestamp;
              dcl-pi *n timestamp(6);
                 mi_time char(8) const;
              end-pi;
              dcl-pr qwccvtdt extpgm;
                 input_format char(10) const;
                 input_value char(8) const;
                 output_format char(10) const;
                 output_variable likeds(qwccvtdt_output);
                 error_code likeds(errorCode);
                 input_time_zone char(10) const;
                 output_time_zone char(10) const;
                 time_zone_info_not_used char(1);
                 length_of_timeZone_Info int(10) const;
                 precision_Indicator char(1) const;
              end-pr;
              dcl-ds errorCode qualified;
                 bytesProvided int(10) inz(0); // Give exception if error
                 bytesAvailable int(10) inz(0);
              end-ds;
              dcl-s not_used char(1);
              dcl-ds qwccvtdt_output qualified;
                 century zoned(1);
                 yy char(2);
                 mm char(2);
                 dd char(2);
                 hh char(2);
                 mi char(2);
                 ss char(2);
                 micro char(6);
              end-ds;
              dcl-ds ts_sep qualified;
                 yyyy char(4);
                    yy_start zoned(2) overlay(yyyy);
                    yy char(2) overlay(yyyy:3);
                 *n char(1) inz('-');
                 mm char(2);
                 *n char(1) inz('-');
                 dd char(2);
                 *n char(1) inz('-');
                 hh char(2);
                 *n char(1) inz('.');
                 mi char(2);
                 *n char(1) inz('.');
                 ss char(2);
                 *n char(1) inz('.');
                 micro char(6);
                 tstamp timestamp(6) pos(1);
              end-ds;
              qwccvtdt ('*DTS'          // Input is MI_TIME from MATTOD
                      : mi_time         // Our parameter (result of MATTOD)
                      : '*YMD'          // Format for the year part
                      : qwccvtdt_output // Output from this API
                      : errorCode       // Set to give an exception if error
                      : '*SYS'          // Input time zone (default)
                      : '*SYS'          // Output time zone (default)
                      : not_used        // Timezone info, ignored if len 0
                      : 0               // Timezone info length
                      : '1');           // Precision in microseconds
              // Assign most of the parts of the returned timestamp
              // to the data structure with the 'real' timestamp
              eval-corr ts_sep = qwccvtdt_output;
              // Change the century (0, 1, 2 ...) to 19, 20, 21 ...
              ts_sep.yy_start = qwccvtdt_output.century + 19;
              return ts_sep.tstamp;
           end-proc;
           dcl-proc print;
              dcl-pi *n;
                 msg varchar(1000) const;
              end-pi;
              dcl-pr printf extproc(*dclcase);
                 msg pointer value options(*string);
                 // This prototype needs at least one parameter
                 // defined with options(*nopass)
                 parm2 pointer value options(*string:*nopass);
              end-pr;
              dcl-c NEWLINE x'15';
              printf (msg + NEWLINE);
           end-proc; 
The sample output is from an actual ILE RPG IV program run on V7R3 POWER7 processor-based server
2020-01-12-10.31.35.625774
2020-01-12-10.31.35.625774
2020-01-12-10.31.35.625775
2020-01-12-10.31.35.625776
2020-01-12-10.31.35.625777
2020-01-12-10.31.35.625777
2020-01-12-10.31.35.625778
2020-01-12-10.31.35.625779
2020-01-12-10.31.35.625780
2020-01-12-10.31.35.625780
2020-01-12-10.31.35.625781
2020-01-12-10.31.35.625782
2020-01-12-10.31.35.625782
2020-01-12-10.31.35.625783
2020-01-12-10.31.35.625784
2020-01-12-10.31.35.625785
2020-01-12-10.31.35.625785
2020-01-12-10.31.35.625786
2020-01-12-10.31.35.625787
2020-01-12-10.31.35.625787
2020-01-12-10.31.35.625788
2020-01-12-10.31.35.625789
2020-01-12-10.31.35.625790
2020-01-12-10.31.35.625790
2020-01-12-10.31.35.625791
2020-01-12-10.31.35.625792
2020-01-12-10.31.35.625792
2020-01-12-10.31.35.625793
2020-01-12-10.31.35.625794
2020-01-12-10.31.35.625795
2020-01-12-10.31.35.625795
2020-01-12-10.31.35.625796
2020-01-12-10.31.35.625797
2020-01-12-10.31.35.625797
2020-01-12-10.31.35.625798
2020-01-12-10.31.35.625799
2020-01-12-10.31.35.625800
2020-01-12-10.31.35.625800
2020-01-12-10.31.35.625801
2020-01-12-10.31.35.625802
2020-01-12-10.31.35.625802
2020-01-12-10.31.35.625803
2020-01-12-10.31.35.625804
2020-01-12-10.31.35.625805
2020-01-12-10.31.35.625805
2020-01-12-10.31.35.625806
2020-01-12-10.31.35.625807
2020-01-12-10.31.35.625807
2020-01-12-10.31.35.625808
2020-01-12-10.31.35.625809
2020-01-12-10.31.35.625809
2020-01-12-10.31.35.625810
2020-01-12-10.31.35.625811
2020-01-12-10.31.35.625812
2020-01-12-10.31.35.625812
2020-01-12-10.31.35.625813
2020-01-12-10.31.35.625814
2020-01-12-10.31.35.625814
2020-01-12-10.31.35.625815
2020-01-12-10.31.35.625816
2020-01-12-10.31.35.625817
2020-01-12-10.31.35.625817
2020-01-12-10.31.35.625818
2020-01-12-10.31.35.625819
2020-01-12-10.31.35.625819
2020-01-12-10.31.35.625820
2020-01-12-10.31.35.625821
2020-01-12-10.31.35.625822
2020-01-12-10.31.35.625822
2020-01-12-10.31.35.625823
2020-01-12-10.31.35.625824
2020-01-12-10.31.35.625824
2020-01-12-10.31.35.625825
2020-01-12-10.31.35.625826
2020-01-12-10.31.35.625827
2020-01-12-10.31.35.625827
2020-01-12-10.31.35.625828
2020-01-12-10.31.35.625829
2020-01-12-10.31.35.625829
2020-01-12-10.31.35.625830
2020-01-12-10.31.35.625831
2020-01-12-10.31.35.625832
2020-01-12-10.31.35.625832
2020-01-12-10.31.35.625833
2020-01-12-10.31.35.625834
2020-01-12-10.31.35.625834
2020-01-12-10.31.35.625835
2020-01-12-10.31.35.625836
2020-01-12-10.31.35.625836
2020-01-12-10.31.35.625837
2020-01-12-10.31.35.625838
2020-01-12-10.31.35.625839
2020-01-12-10.31.35.625839
2020-01-12-10.31.35.625840
2020-01-12-10.31.35.625841
2020-01-12-10.31.35.625841
2020-01-12-10.31.35.625842
2020-01-12-10.31.35.625843
2020-01-12-10.31.35.625844
2020-01-12-10.31.35.625844
Press ENTER to end terminal session.
Example in ILE C and C++ programming language.
 
/*                                                                        
   This program calls MI instruction MATTOD (Materialize Time-of-Day Clock)
   multiple times in a loop, stores the readings in an array as they are  
   generated, then displays them.  Before displaying the readings, the
   program uses API Qp0zCvtToTimeval to convert them to timestamps; the
   timestamp format is:
   xxxxxxxxxx.yyyyyy
   where

   xxxxxxxxxx is calendar time: this is the number of seconds that have
   elapsed since EPOCH, which is 00:00:00, January 1, 1970 Universal
   Coordinated Time (UTC); this is explained in more detail in the manual
   "ILE C for AS/400 Run-Time Library Reference" under function time()

   yyyyyy is the number of microseconds, +/- 8 microseconds.
*/                                                                        
     #include <stdio.h>                                                    
     #include <qp0z1170.h>                                                
     #include <mimchint.h>                                                
     #include <errno.h>                                                    
                                                                           
/* Define the array to store 100 timestamps. */                            
     #define arraysize 100                                                
                                                                           
     int main(void) {                                                      
     _MI_Time mt[arraysize];                                              
     struct timeval tv;                                                    
     int rc;                                                              
     int counter;                                                          
                                                                           
/* Call MATTOD until the array is filled. */                                
    for(counter = 0; counter < arraysize; counter++)                        
       {                                                                    
        mattod(mt[counter]);                                                
       };                                                                    
                                                                             
/* Convert each reading in the array to a regular timestamp, then display. */
    for(counter = 0; counter < arraysize; counter++)                        
       {                                                                    
        rc = Qp0zCvtToTimeval(&tv, mt[counter], QP0Z_CVTTIME_TO_TIMESTAMP);  
/* If conversion to timestamp was successful, display result */              
        if(rc==0) {                                                          
            printf("timeval timestamp: %u.%06u\n",                          
                    tv.tv_sec, tv.tv_usec);                                  
        }                                                                    
/* Else display/return error code */                                        
        else {                                                              
            printf("Qp0zCvtToTimeval() failed, errno = %d\n",                
                    errno);                                                  
            return -1;                                                      
        }    
       };    
             
    return 0;
}    
The sample output is from an actual ILE C/C++ program run on V7R3 POWER7 processor-based server.
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708784
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708792
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708800
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708808
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708816
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708824
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
timeval timestamp: 1578848870.708832
Press ENTER to end terminal session.

[{"Line of Business":{"code":"LOB57","label":"Power"},"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SWG60","label":"IBM i"},"ARM Category":[{"code":"","label":""}],"Platform":[{"code":"PF012","label":"IBM i"}],"Version":"7.4.0;7.3.0;7.2.0;7.1.0;6.1.0"}]

Historical Number

27940528

Document Information

Modified date:
12 July 2021

UID

nas8N1016862