Time zone Ambiguities
I was asked recently to organize a meeting with someone in the "UTC-7" time zone (US mid west). This is a common way to represent a time zone, but is not definitive, as can be seen in the highlighted zone below.
POSIX time zone ambiguitiesIn addition to the general confusion above, POSIX adds its own layer of obtuseness, as one refers to the "UTC-7" zone as "UTC+7".
$ TZ=UTC+7 date +%z -0700The '+' offset format specified by POSIX is reversed from common sense and from all other formats, including all `date` output formats as can be seen above. Note the "UTC" above is not significant¹, and only used to identify the zone in any output, so the offset "indicates the value added to the local time to arrive at Coordinated Universal Time.". See man timezone for details of the $TZ formats.
I guess as an extension to POSIX, libc could treat "UTC" or "GMT" in $TZ specially, and reverse the sense of any offset. But that would add another inconsistency and also one would have to use the offset like "-0700" above, in the output, rather than "UTC".
¹ Note the "UTC" portion above can be significant, which is another reason to avoid these abbreviated timezone specifications. Consider the following (some of which match entries in /usr/share/zoneinfo/) confusing output:
$ TZ=CEST date # No match Tue Sep 27 18:03:05 CEST 2011 $ TZ=CET date # Match and change Tue Sep 27 20:03:09 CEST 2011 $ TZ=GB-Eire+1 date # No zone reported Tue Sep 27 22:02:49 2011 $ TZ=CET+1 date # Zone reported (no offset) Tue Sep 27 20:03:16 CET 2011 $ TZ=Japan+1 date # Match and no change Tue Sep 27 21:02:54 Japan 2011 $ TZ=Japan date # Match and change Wed Sep 28 07:03:53 JST 2011 $ TZ=Asia/Japan date # No match (Tokyo required) Wed Jun 20 07:53:15 Asia 2012
Note `date` doesn't warn about unmatched zones because there is no portable API to know if a TZ is not matched. This applies to the following TZ format too.
Location based zonesSo due to the ambiguity of the "offset based" time zones described above, it's better to use a "location based" zone, which are not specified by POSIX but are available on GNU/Linux. For example one can specify TZ=America/Los_Angeles which will take daylight savings time into account (which happens at different times in various places, if at all). To select from the available locations, use the tzselect utility. The following example uses this format to show the local time in Phoenix corresponding to 7PM in Dublin.
$ TZ="America/Phoenix" date -R --date='TZ="Europe/Dublin" 19:00 tomorrow' Tue, Jun 7 11:00:00 -0700
Other time zone gotchasEven when not directly specifying TZ, one must still be aware of its effects. For example, consider a script that needs to exit unless it's the last day of the month:
[ $(date -d tomorrow +%d) = '01' ] || exitThe above is susceptible to DST fuzzing, with the behavior, on the day of the DST transition, depending on when the script is run. To make it independent of when the script is run, you might think you could use:
[ $(date -d '12:00 +1 day' +%d) = '01' ] || exitHowever the +1 is taken as a timezone associated with the time. Thus what you really want is:
[ $(date -d '12:00 today +1 day' +%d) = '01' ] || exitAlso note that time zone peculiarities can be introduced by higher level components in the system. For example see this excellent article on Dealing with Timezones in Python.