MC Press Online

Wednesday, Jun 28th

Last updateTue, 27 Jun 2017 9am

You are here: Home ARTICLES Programming APIs The API Corner: What Time Zone Do You Want That Date and Time In?

Programming / APIs

The API Corner: What Time Zone Do You Want That Date and Time In?

SUPPORT MC PRESS - VISIT OUR SPONSORS

NEW BOOK!

IBM i Security Administration and Compliance


ORDER YOUR COPY

*******************

Click for this Month's

Bookstore Special Deals


Today, we'll look at more uses for the Convert Date and Time Format API.

 

Last month, in How Do You Want That Date and Time?, we used the first five parameters of the Convert Date and Time Format (QWCCVTDT) API to format a date and time value stored in a *DTS format to a YYYYMMDDHHMMSS format that's much friendlier to work with. This month, we'll look at the two optional parameter groups of the API. But first some background.

 

One of the companies I work with supports multiple plants on the same system, with not all of the plants necessarily being in the same time zone. They, however, want to provide date and time values on various panels and reports in the local time zone of the plant a user is associated with. They in the past have done this by storing a time zone offset value in each plant library. So, for instance, if the system is in Mechanicsburg, Pennsylvania, then facilities in New York would have an offset value of 0, facilities in Amarillo, Texas, would have an offset value of -1, and so on. When an application needs the current date and time, it simply calls a common function and the function accesses the system local time and then adjusts it based on the offset found in the plant library. This approach is fast and works quite well in a Monday thru Friday (or Saturday) 8 to 5 environment, but only 99.97+% of the time in a 24x7 environment. For instance, this past March 8, Amarillo reported a problemnamely, that times such as 1:15 a.m. were showing up as being 2:15 a.m. This problem was due to March 8, 2015, being the start of Daylight Saving Time (DST) in the United States. At 2:00 a.m., Mechanicsburg local time moved forward by one hour to 3:00 a.m., causing the Amarillo calculation to take a local system time of say 3:15 a.m., add an hour offset value of -1, and then return 2:15 a.m.. The problem went away after 60 minutes when Amarillo also started DST at 2:00 a.m. local time.

 

The optional parameter groups of the QWCCVTDT API allow you to correctly (100% of the time rather than 99.97+% of the time) convert date and time values from one time zone to another. Optional parameter group one defines five parameters.

 

The first optional parameter is the input time zone. This is a Char(10) input value that defines the time zone associated with the time value provided in required parameter number two if the special value *CURRENT is not being used for the first required parameter. In addition to supporting the name of a time zone (*TIMZON) object, the API also supports the special values of: 

  • *SYS to interpret the input value as being in the time zone specified by the QTIMZON system value. This is the default value if the parameter is not passed to the API.
  • *UTC to interpret the input time value as being a Coordinated Universal Time (UTC) value.
  • *JOB to interpret the input time value as being in the time zone specified by the time zone job attribute.

The second optional parameter is the output time zone. This parameter identifies the time zone you want the returned output value of required parameter four to be in. The parameter is defined the same as the first optional parameter and supports the same list of special values.

 

The third and fourth optional parameters allow you to also retrieve information about the time zone identified by the second optional parameter (the output time zone). The third parameter is a variable-length receiver variable where the API can return information such as the name of the time zone used, whether or not the time zone is currently in DST, and the full name of the time zone. The fourth optional parameter is a Bin(4) input value providing the length of the receiver variable. A value of 0, which is what we'll be using, indicates that no time zone information is to be returned to the application.

 

The fifth optional parameter is a Char(1) input value indicating the precision of the input and output values (required parameters two and three), respectively. A value of '0' indicates that the values have a precision in milliseconds, a value of '1' that the values have a precision of microseconds.

 

With that introduction, the following program (CvtDat2) calls the QWCCVTDT API twice and dsplys the resulting local current times for Mechanicsburg and Amarillo, respectively. The time zone for Mechanicsburg is QN0500EST3 and the time zone for Amarillo QN0600CST2. The WRKTIMZON command can be used to see what all time zones are defined for your system and what DST rules are defined, if any, for the various time zones.

 

h dftactgrp(*no)                                                  
                                                                  
d CvtDat2         pr                                              
                                                                  
d CvtDat2         pi                                              
                                                                  
 **************************************************************** 
                                                                  
d CvtDatTim       pr                  extpgm('QWCCVTDT')          
d  InpFmt                       10a   const                       
d  InpValue                     20a   const options(*varsize)     
d  OutFmt                       10a   const                       
d  OutValue                     20a   options(*varsize)           
d  ErrCde                             likeds(QUSEC)               
d  InpTZ                        10a   const options(*nopass)      
d  OutTZ                        10a   const options(*nopass)      
d  TZInfo                        1a   const options(*nopass)      
d  LenTZInfo                    10i 0 const options(*nopass)      
d  PrecInd                       1a   const options(*nopass)      
d  InpTimInd                     1a   const options(*nopass)       
                                                                   
 ****************************************************************  
                                                                   
d YYMDValue       s             20a                                
                                                                   
 ****************************************************************  
                                                                   
 /copy qsysinc/qrpglesrc,qusec                                     
                                                                   
 ****************************************************************  
                                                                   
 /free                                                             
                                                                   
  CvtDatTim('*CURRENT' :' '                                        
            :'*YYMD' :YYMDValue :QUSEC                             
            :' ' :'QN0500EST3'                                     
            :' ' :0 :'0');                                         
  dsply (%char(%date(%subst(YYMDValue :1 :8) :*ISO0)) + ' ' +      
         %char(%time(%subst(YYMDValue :9 :6) :*HMS0)));            
                                                               
  CvtDatTim('*CURRENT' :' '                                    
            :'*YYMD' :YYMDValue :QUSEC                         
            :' ' :'QN0600CST2'                                 
            :' ' :0 :'0');                                     
  dsply (%char(%date(%subst(YYMDValue :1 :8) :*ISO0)) + ' ' +  
         %char(%time(%subst(YYMDValue :9 :6) :*HMS0)));      

 

  *inlr = *on;                                                    
  return;                                                         
                                                                  
  // ************************************************************ 
                                                                  
  begsr *inzsr;                                                   
                                                                  
    QUSBPrv = 0;                                                  
                                                                  
  endsr;                                                          
                   
 /end-free          
                     
                                          

Calling the program results in the following messages:

 

DSPLY  2015-07-12 07.07.45    
DSPLY  2015-07-12 06.07.45    

 

The messages indicate that it is currently 7:07 a.m. on July 12, 2015, in Mechanicsburg (or more properly in the Eastern Time Zone) and 6:07 on July 12 in Amarillo (or really anywhere in the Central Time Zone).

 

We'll now "pretend" it's 3:15 a.m. in Mechanicsburg by changing the two API calls to the following:

 

  CvtDatTim('*YYMD' :'20150308031500000'                       
            :'*YYMD' :YYMDValue :QUSEC                         
            :'QN0500EST3' :'QN0500EST3'                        
            :' ' :0 :'0');                                     
  dsply (%char(%date(%subst(YYMDValue :1 :8) :*ISO0)) + ' ' +  
         %char(%time(%subst(YYMDValue :9 :6) :*HMS0)));        
                                                               
  CvtDatTim('*YYMD' :'20150308031500000'                       
            :'*YYMD' :YYMDValue :QUSEC                         
            :'QN0500EST3' :'QN0600CST2'                        
            :' ' :0 :'0');                                     
  dsply (%char(%date(%subst(YYMDValue :1 :8) :*ISO0)) + ' ' +  
         %char(%time(%subst(YYMDValue :9 :6) :*HMS0)));       

 

Now, calling the program results in the following messages:

 

DSPLY  2015-03-08 03.15.00    
DSPLY  2015-03-08 01.15.00   

 

This shows that it is currently 3:15 a.m. on March 8, 2015, in Mechanicsburg and 1:15 a.m. on March 8 in Amarillo. Note that the Amarillo local time is now correct.

 

We do still have a potential problem though, and that is when DST ends. In 2015, come November 1, the Mechanicsburg local time at 2:00 a.m. will fall back to 1:00 a.m. so there will be two instances of the time range 1:00 a.m. to 2:00 a.m. In the first instance of 1:15 a.m. for Mechanicsburg, the Amarillo local time is 00:15 a.m. while in the second instance of 1:15 a.m. it will also be 1:15 a.m. Amarillo time. How does the QWCCVTDT API know which instance (the first or second) is to be used when processing the input time value? First, the good news: if we're using the input time value of *CURRENT, the system will take care of this for us. But if we are providing a discrete value, as we are in the previous example when specifying '20150308031500000', then there are a couple of ways to handle this.

 

One approach is with the second optional parameter group of the QWCCVTDT API. Optional parameter group 2 defines one parameter. A Char(1) Input time indicator that, when set to '0', means we are in the second (or Standard Time) instance and if '1' we are in the first (or DST) instance. The default is '1'. This is one of the pieces of information available to you with the third and fourth parameters of optional parameter group 1.

 

The second approach, and the one I prefer, is to simply not use an input time zone that observes DST when working with discrete values. There are several such time zones on the system, with Q0000UTC being one, and in the case of QWCCVTDT, there is support for the special value *UTC as a time zone so you don't even have to remember the *TIMZON object name.

 

We can change our two calls to QWCCVTDT to use *UTC based values:

 

  CvtDatTim('*YYMD' :'20151101051500000'                      
            :'*YYMD' :YYMDValue :QUSEC                        
            :'*UTC' :'QN0500EST3'                             
            :' ' :0 :'0');                                    
  dsply (%char(%date(%subst(YYMDValue :1 :8) :*ISO0)) + ' ' + 
         %char(%time(%subst(YYMDValue :9 :6) :*HMS0)));       
                                                              
  CvtDatTim('*YYMD' :'20151101051500000'                      
            :'*YYMD' :YYMDValue :QUSEC                        
            :'*UTC' :'QN0600CST2'                             
            :' ' :0 :'0');                                    
  dsply (%char(%date(%subst(YYMDValue :1 :8) :*ISO0)) + ' ' + 
         %char(%time(%subst(YYMDValue :9 :6) :*HMS0)));       

 

Now, results in the two messages:

 

DSPLY  2015-11-01 01.15.00    
DSPLY  2015-11-01 00.15.00    

 

The API is returning the correct local times for the first instance of 1:15 a.m. in Mechanicsburg. Changing the discrete value '20151101051500000' to '20151101061500000' (adding one hour so that we're in the second instance of 1:15 a.m. in Mechanicsburg) results in the correct values of:

 

DSPLY  2015-11-01 01.15.00    
DSPLY  2015-11-01 01.15.00    

 

And adding yet another hour ('20151101071500000') to the UTC time value results in the local times of:

 

DSPLY  2015-11-01 02.15.00    
DSPLY  2015-11-01 01.15.00    

 

Amarillo is now on Standard Time and seeing the second instance of 1:15 a.m..

 

Using the QWCCVTDT API, and its time zone support, enables the correct representation of local times in a distributed environment and does not require you to personally handle the various quirks of DST. In the case of our original problemthe storing of an appropriate numeric offset value (0 for Mechanicsburg, -1 for Amarillo) per plantwe could change to storing the appropriate *TIMZON object name for the plant, use the API, and be done with it (with 100% accuracy).

 

Have Some System API Questions?

As usual, if you have any API questions, send them to me at This email address is being protected from spambots. You need JavaScript enabled to view it.. I'll see what I can do about answering your burning questions in future columns.

 

Bruce Vining

Bruce Vining is president and co-founder of Bruce Vining Services, L.L.C., a firm providing contract programming and consulting services to the System i community (www.brucevining.com). He began his career in1979 as an IBM Systems Engineer in St. Louis, Missouri, and then transferred to Rochester, Minnesota, in 1985, where he continues to reside. From 1992 until leaving IBM in 2007, Bruce was a member of the System Design Control Group responsible for OS/400 and i5/OS areas such as System APIs, Globalization, and Software Serviceability. He is also the designer of Control Language for Files (CLF).

 

A frequent speaker and writer, Bruce can be reached at bvining@brucevining.com.

 

MC Press books written by Bruce Vining available now on the MC Press Bookstore.

 

IBM System i APIs at Work IBM System i APIs at Work

Master APIs with this in-depth, example-rich exploration into these powerful tools.

List Price $89.95
Now On Sale
 
BLOG COMMENTS POWERED BY DISQUS