Generating a date in UTC Date Format
The data format for an external entity we were supplying data to had changed. They changed the date format from the international YYYYMMDD format to the UTC format. D3 does not have an intrinsic conversion for this format, so I had to come up with a way of generating this date format.
After some research, I found a command using PowerShell that could provide me with this date format, but on execution from within D3 I found it to be too slow, especially in a loop. I needed to use only D3 to create the date format to ensure optimal speed.
One of the things to keep in mind is whether daylight savings time is in effect (or not). Again, D3 does not provide this info and calling a Powershell script was just too slow. I had to find a way to store a flag in D3 which could be used by a D3 subroutine to know about daylight savings time (DST) and produce the date in UTC format. My idea was to set a DST flag in D3 once a day when the user logs in. This flag can then be read as often as required by D3 with little effect on a loop.
This lead me to further research and I found a Python script to determine if DST is in effect. I made a few modifications specifically for our time zone in Adelaide, Australia:
# Python script to determine whether or not daylight savings is in effect.
# Returns the values True or False.
# 22/09/2020 WHK with some help from the internet... :)
aware_dt = timeZone.localize(dt)
return aware_dt.dst() != datetime.timedelta(0,0)
timeZone = pytz.timezone("Australia/Adelaide")
dt = datetime.datetime.now()
We're using D3 V9.2.2 and don't have easy access to running Python scripts, so I created a DOS batch wrapper to invoke the script.
rem Invoke a Python script that checks if Daylight Savings Time is in effect.
rem Returns "True" or "False".
rem 23/09/2020 WHK
rem Note: This method was chosen because when D3 shells out it uses the pick user's
rem environment variables and the PATH does not include the path to Python.
rem This batch file adds the Python path before executing the Python script
rem to determine if daylight savings time is in effect.
This can be invoked using the D3 shell prefix (!) and a BASIC EXECUTE command like this:
VERB = '!c:\Scripts\is_dst'
EXECUTE VERB CAPTURING TEXT
DST = (TEXT = 'True')
Now that I have the DST flag, I can save it to a control file and read it as often as I like with little impact on a loop's speed. The above code was embedded in the login program and the flag written to a system control file item, e.g. SDCONTROL DAYLIGHT.SAVINGS.TIME.FLAG.
From here on it's fairly easy to create the UTC time formatted date. See the subroutine below:
001 SUBROUTINE PSS.GEN.UTC( UTC.DATE )
005 * Subroutine: PSS.GEN.UTC
007 * Description: Convert a date to Universal Time Code (UTC) or provide
008 * today's date/time as UTC.
010 * Author : Walter H. Kiess
011 * Dated : 23/09/2020
012 * Version: 2.0
016 * Parameters
017 * ==========
019 * INPUT: UTC.DATE - <1> Date /time to convert to UTC. Date may be in
020 * OCONV format, e.g. 31/12/2018, or
021 * 31/12/2018 8:34:33 or internal date only format
022 * e.g. 18524
023 * <2> Optional: "FRAC" to append fraction of a second
025 * OUTPUT: UTC.DATE - Converted date/time
029 * Revisions:
031 * WRnnnn: dd/mm/yy xxx Description
034 $options ext
036 IF NOT(ASSIGNED(UTC.DATE)) THEN UTC.DATE = '' ;* Prevent errors, default to today.
038 * Set timezone offset according to daylight savings time setting
040 CALL PSS.IS.DST( DST ) ;* Is Daylight Savings Time in effect?
041 IF DST THEN
042 TZ.OFFSET = 10.5
043 END ELSE
044 TZ.OFFSET = 9.5
047 IF UTC.DATE<2, 1, 1> = 'FRAC' THEN
048 UTC.DATE = UTC.DATE<1, 1, 1>
049 FRAC = 1 ;* Add fractions of a second to time
050 END ELSE
051 FRAC = 0
054 * Check if supplied date is Null, ICONV or OCONV format and set to ICONV format
056 IF UTC.DATE = '' THEN ;* No date supplied, use today.
057 IDATE = DATE()
058 ITIME = TIME()
059 END ELSE
060 IF UTC.DATE = UTC.DATE'MCN' THEN ;* ICONV format, save it.
061 IDATE = UTC.DATE
062 ITIME = TIME()
063 END ELSE ;* OCONV format, convert it.
064 IF INDEX(UTC.DATE, ' ', 1) THEN ;* A time was also specified,
065 OTIME = FIELD(UTC.DATE, ' ', 2) ;* extract time...
066 ITIME = ICONV(OTIME, 'MT') ;* convert time to ICONV
067 UTC.DATE = FIELD(UTC.DATE, ' ', 1) ;* extract date...
068 IDATE = ICONV(UTC.DATE, 'D') ;* convert date to ICONV
069 END ELSE ;* No time specified,
070 IDATE = ICONV(UTC.DATE, 'D') ;* use current time.
071 ITIME = TIME()
076 ITIME -= TZ.OFFSET * 60 * 60 ;* Apply timezone offset
077 IF ITIME <= 0 THEN ;* Adjust time to yesterday
078 ITIME += 86400
079 IDATE -= 1
082 * Assemble UTC date/time
084 UTC.DATE = OCONV(IDATE, 'D4Y')'R%4': '-': OCONV(IDATE, 'DM')'R%2': '-': OCONV(IDATE, 'DD')'R%2': 'T': OCONV(ITIME, 'MTS'):
088 *~~~~~~~~~~~~~~~~~~~~~~~~ END OF SUBROUTINE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Note the use of a subroutine to read the flag. I did this as the original implementation used a PowerShell script to do this but I found it too slow when used in a loop. I didn't want to break any other functionality in the system so I simply replaced the functionality of the subroutine to yield the same, but faster, result.
001 SUBROUTINE PSS.IS.DST( OUT.DST )
005 * Subroutine: PSS.IS.DST
007 * Description: Is Daylight Savings Time in effect?
009 * Author : Walter H. Kiess
010 * Dated : 23/09/2020
011 * Version: 1.1
013 * Note: is_dst is a DOS batch file which calls a Python script to determine
014 * whether Daylight Savings Time is in effect. The batch file was
015 * necessary as it adds the Python path to the environment to enable
016 * the system to run the Python script.
018 * Note2: As I was developing this concept I realised this sub could be called
019 * many times in a loop depending on it's usage. Shelling out to
020 * Windows to check for DST would take too long so I moved the test
021 * to the login program (SDBP) SDSGON which now sets the flag
022 * (SDCONTROL) DAYLIGHT.SAVINGS.TIME.FLAG to 1=Yes or 0=No. This is
023 * much quicker to read using an OCONV than shelling out.
025 * I decided to keep using the sub as a simple standard way of obtaining
026 * the flag without having to remember where the flag was stored.
030 * Parameters
031 * ==========
033 * OUTPUT: OUT.DST - Flag indication state of Daylight Savings Time:
034 * 0=False, 1=True, i.e. in effect.
038 * Revisions:
040 * WRnnnn: dd/mm/yy xxx Description
044 $options ext
046 *** VERB = '!c:\Scripts\is_dst' ;* Is Daylight Savings Time in effect?
047 *** EXECUTE VERB CAPTURING TEXT
048 *** IF TEXT = 'True' THEN
049 *** OUT.DST = 1 ;* All this code was transfered to SDBP SDSGON (the login program)
050 *** END ELSE
051 *** OUT.DST = 0
052 *** END
054 OUT.DST = OCONV('DAYLIGHT.SAVINGS.TIME.FLAG', 'TSDCONTROL;X;;1')
055 OUT.DST = (OUT.DST = '1') ;* Force false in case the flag is missing
059 *~~~~~~~~~~~~~~~~~~~~~~~~ END OF SUBROUTINE ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
So there you have it. A simple call to PSS.GEN.UTC( UTC.DATE ) will return a date in UTC format by converting a supplied value or now, if none provided. And as a bonus, a call to PSS.IS.DST( IS.DST ) will tell you if daylight savings time is in effect.
Hopefully, this will help someone in a similar situation with a solution.Disclaimer: Feel free to use this code, as is, with no warranties intended, implied or given, at your own risk.
77 4th AvenueWaltham, MA 02451 USA
Rocket Support Community
All Support Offerings
About Rocket Software
Training and Services
Forum Terms and Conditions
Contact Forum Moderator