Wednesday, October 4, 2023

Determining the time zone, and calculating the time in another country

I was asked if there is a way to calculate the current time in Japan, in an IBM i partition in the USA. To add to the complication in doing this the use of Daylight Savings Time, DST, has to be handled. Most places in the USA observe DST, not all other countries do.

Every IBM i partition has a set of system values that are related date and time. Two of these are particularly relevant here:

  • QTIMZON:  Time zone
  • QUTCOFFSET:  UTC offset, hours and minutes different from UTC. UTC the same as GMT, Greenwich Mean Time

I can retrieve these two system values with a SQL statement using the SYSTEM_VALUE_INFO View:

01  SELECT SYSTEM_VALUE_NAME,CURRENT_CHARACTER_VALUE
02    FROM QSYS2.SYSTEM_VALUE_INFO 
03   WHERE SYSTEM_VALUE_NAME IN ('QTIMZON','QUTCOFFSET') 
04   ORDER BY 1

The results are:

SYSTEM_     CURRENT_
VALUE_      CHARACTER_
NAME        VALUE
----------  ----------
QTIMZON     QN0600CST2
QUTCOFFSET  -0500

The IBM i partition I used here is on US Central Time, which is what the QN0600CST2 stands for. US Central Time is normally -6 hours different UTC, except when it is DST then it is -5 hours.

Fortunately IBM has a web page that describes what all the Time Zone means. It is found here.

For the time zone code QN0600CST2 the entry on that page is:

Time zone object QN0600CST2
Offset from UTC -6:00
Standard time name Central Standard Time (CST)
Daylight Savings time name Central Daylight Time (CDT)
DST start Second Sunday in March at 2:00 AM
DST end First Sunday in November at 2:00 AM
Message id for standard time description* CPX0921
Message id for DST description* CPX0922

The message ids, marked with *, are different depending upon the time zone. If you want to see what they all are use the MESSAGE_FILE_DATA View:

01  SELECT MESSAGE_ID,
02         MESSAGE_SECOND_LEVEL_TEXT
03    FROM QSYS2.MESSAGE_FILE_DATA
04   WHERE MESSAGE_FILE_LIBRARY = 'QSYS'
05     AND MESSAGE_FILE = 'QCPFMSG'
06     AND MESSAGE_ID BETWEEN 'CPX091A' AND 'CPX0969'
07     AND MESSAGE_TEXT = ' '

Line 6: All the time zone message ids are in this range. But there are some other message ids that are not related to time zones in that range.

Line 7: Fortunately all the time zone messages had a blank message text column.

There are too many to list here. Below are the entries for the US Central Time:

MESSAGE_ID   MESSAGE_SECOND_LEVEL_TEXT
----------   -------------------------------
CPX0921      CST       Central Standard Time
CPX0922      CDT       Central Daylight Time

Now I know what time zone I am in and its difference from UTC how can I use that view the time in UTC or for another time zone?

I don't have to use any of the results from the system values. There is a special register called CURRENT_TIMEZONE, it returns the UTC offset. I can use it thus:

01  SELECT CURRENT_TIMESTAMP AS "My time",
02         CURRENT_TIMEZONE AS "Time zone",
03         CURRENT_TIMESTAMP - CURRENT_TIMEZONE AS "UTC time"
04    FROM SYSIBM.SYSDUMMY1

I used a Select statement, rather than VALUES, as I can give the columns my choice of headings.

Line 3: Calculation UTC time is as simple as subtracting the time zone from the current timestamp.

My results are:

My time                     Time zone  UTC time
--------------------------  ---------  --------------------------
2023-09-21 12:53:51.010068     -50000  2023-09-21 17:53:51.010068

The time zone is shown as -5 hours, which is Central DST, but there are other numbers that follow it. There are some places in the world where their time zone is hours and minutes different from UTC, for example: India is +5:30, Western Australia is +8:45. Seconds different from UTC? No-one is that.

The original question was to calculate the time in Japan, which is +9 hours UTC. Fortunately Japan does not observe DST. My calculation for display its time would be:

(local_time – time_zone) + (9 hours)

In an SQL statement this can be expressed as:

01  SELECT CURRENT_TIMESTAMP AS "My time",
02         (CURRENT_TIMESTAMP - CURRENT_TIMEZONE) + 9 HOURS
              AS "Japan time"
03    FROM SYSIBM.SYSDUMMY1

The result is:

My time                      Japan time
--------------------------   --------------------------
2023-09-21 13:26:20.864599   2023-09-22 03:26:20.864599

In my experience only IT people use the timestamps. Everyone else uses a separate date and time. I can modify the previous SQL statement to give me those:

01  SELECT CURRENT_TIMESTAMP AS "My time",
02         DATE((CURRENT_TIMESTAMP - CURRENT_TIMEZONE) + 9 HOURS)
                   AS "Japan date",
03         TIME((CURRENT_TIMESTAMP - CURRENT_TIMEZONE) + 9 HOURS)
                   AS "Japan date"              
04    FROM SYSIBM.SYSDUMMY1

Line 2: I have converted the timestamp to a date with the DATE function.

Line 3: Converted the timestamp to a time with TIME.

My time                     Japan date  Japan time
-------------------------   ----------  ---------
2023-09-21 13:26:20.864599   2023-09-22  03.26.20

That was simple for Japan as I do not have to consider DST.

I decided to make this better by creating a User Defined Function, UDF, to return the timestamp for another place. This post is long enough as it is. I have created "Part two" that demonstrates what I did to create the UDF. Which is coming soon.

 

This article was written for IBM i 7.5, and should work for some earlier releases too.

No comments:

Post a Comment

To prevent "comment spam" all comments are moderated.
Learn about this website's comments policy here.

Some people have reported that they cannot post a comment using certain computers and browsers. If this is you feel free to use the Contact Form to send me the comment and I will post it for you, please include the title of the post so I know which one to post the comment to.