Some of the APIs we use, such as QUSLOBJ (List Object Information), create a list of object names and their attributes. In that list, the object creation timestamp (subfield QUSCDT00) and last changed timestamp (subfield QUSCDT01) are generated. These fields are defined as 8-byte character fields and referred to as "timestamps." But they are not formatted in what we traditionally think of as a timestamp or even a date or time format. Instead, they are in what is sometimes referred to as "system date format" or "system timestamp format." But the internal description is known as "MI time" format.
Standard time format is how the MI documentation sometimes refers to this value. However, the API documentation and many MI instructions (in both C and MI languages) refer to it as MI time. There is also an occasional reference to system *DTS format.
The problem you have as an RPG IV programmer is that this format cannot be easily converted to a true RPG-style timestamp (Z data type) or date and time value.
The MI time (as we'll refer to it from here out) is currently a 49-bit value that contains the number of microseconds since three minutes past noon on August 23, 1928.
These 49 bits are stored in a 64-bit (8-byte) unsigned integer. In RPG IV, this means it is a 20U0 value.
The rightmost 15 bits are currently unused, so you have to shift the bits to the right to get an accurate numeric value. In C++, you would use two greater-than symbols (>>) to accomplish this, but in RPG IV, you have to use grunt coding techniques.
The following source code illustrates the miTimeToDTS() subprocedure. It converts the 8-byte character value containing an MI time into a true RPG IV Z data type. From that value, you can move the date into a date field and the time into a time field. Or you could always modify the code to return separate date and time variables.
As a point of completeness, you can use the QWCCVTDT API to achieve similar results. To call this API to convert an MI time value to a data structure containing the date, time, and milliseconds value, you can use the following syntax:
The prototype for this API follows:
D inFmt 10A Const
D inDate 64A Const
D outFmt 10A Const
D outDate 64A OPTIONS(*VARSIZE)
D APIerrorDS LikeDS(QUSEC) OPTIONS(*VARSIZE)
The inDate and outDate parameters are not strictly defined as 64-bytes in length; however, that size seems to work for all variations of this API.
The outDate (returned value) parameter is defined as follows:
D date 8S 0
D time 6S 0
D milliSeconds 3S 0
If you run into the need to convert from MI time to RPG IV date data types, these two routines may be useful.
H Copyright('(c) 2006 by Robert Cozzi, Jr.')
D MiTimeToDTS PR Z
D miTime 8A Const
D MI_TIME_T DS Qualified Based(ptr_Nothing)
D char 8A
D microSecs 20U 0 Overlay(char)
D miTime S 8A
D myDTS S Z
// This test code to validate that the
// MiTimeToDTS() subprocedure is working.
// Results are identified in comments.
/free
// 01/01/2000 00:00:00.000000
miTime = X'8000000000000000';
myDTS = MiTimeToDTS(miTime);
// 01/01/1970 00:00:00.000000
miTime = X'4A2FEC4C82000000';
myDTS = MiTimeToDTS(miTime);
// 07/07/2053 20:57:40.263928
miTime = X'DFFFFFFFFFFF8000';
myDTS = MiTimeToDTS(miTime);
// 08/23/1928 12:03:06.314752
miTime = X'0000000000000000';
myDTS = MiTimeToDTS(miTime);
/end-free
C eval *INLR = *ON
P MiTimeToDTS B Export
D MiTimeToDTS PI Z
D miTime 8A Const
D myTime DS LikeDS(MI_TIME_T) Inz
D int S 10U 0
D myDTS S Z Inz
D nSmallSecs S 15P 0
D baseDts S Z Inz(Z'1928-08-23-12.03.06.314752')
D MicroSecs S 20U 0
D decSecs DS Qualified INZ
D nDuration 20S 0
D nSecs 20S 6 Overlay(nDuration)
D nMicroSecs 6S 0 Overlay(nDuration:15)
/free
myTime = miTime;
// Shift the miTime right, 15 bits
microSecs = %Div(myTime.microSecs:4096);
// Map the microseconds to decimal
decSecs.nDuration = microSecs;
// Add the microSeconds to the base DTS.
myDts = baseDTS + %MSeconds(decSecs.nMicroSecs);
// Clear the microSeconds.
decSecs.nMicroSecs = 0;
// Using DS trickery, copy the "seconds"
// to a work field whose size is compatible
// with the MI duration value (15P0 max).
// nSmallSecs = decSecs.nSecs;
// Add the seconds to the dts value and we're done!
myDts = myDTS + %Seconds(%dec(decSecs.nSecs:15:0));
return myDTS;
/end-free
P MiTimeToDTS E
Bob Cozzi is a programmer/consultant, writer/author, and software developer of the RPG xTools, a popular add-on subprocedure library for RPG IV. His book The Modern RPG Language has been the most widely used RPG programming book for nearly two decades. He, along with others, speaks at and runs the highly-popular RPG World conference for RPG programmers.
LATEST COMMENTS
MC Press Online