whatupmiked intersection between networking, not working, and software


Time is on my side

At least once every few days for the last several years I’ve been going to worldtimebuddy to figure out when to schedule meetings. Awareness of the different time zones is useful when I’m living in GMT+0:00, working with customers in Europe and Asia, then inevitably coordinating with folks in California. Lately I’ve been spending more time on the command line and I got to thinking, why not just use a built-in tool to do this for me?

Well, it turned out to be a little more complicated than I thought! So obviously… blog.

I’ve been trying to work with either ubiquitous commandline utilites, builtins, or coreutils. That way when I can use the same skillset in a debian, redhat, or macosx environment. I use the date command to get the time on unix systems, so it seems like a reasonable place to start.

First hiccup, not all terminals are equal! Updated versions of RHEL7 and Ubuntu 14 are using GNU coreutils 8.22 and 8.25 respectively for their version of date, but my macbook is using a BSD version from August 16, 2007. The behavior of the date command is slightly different between these versions. Easy enough to solve, right? I’ll just ‘brew install coreutils’ on the mac and continue with my project. Turns out the name is slightly different though, gdate instead of date.

The uname command returns ‘Darwin’ on mac, so I will create a conditional that will use a different command depending on the shell.

if [ $(uname) == "Darwin" ]; then
    gdate $@
    date $@

The first step was to determine how to pass a time zone! The manual page for date seemed to point in a good direction: > Show the time on the west coast of the US (use tzselect(1) to find TZ) > $ TZ=‘America/Los_Angeles’ date

So, testing that:

$ date
Sun Mar  5 19:21:37 GMT 2017
$ TZ='America/Los_angeles' date
Sun Mar  5 11:21:47 PST 2017

Presto, the time for London (GMT) and a different time zone, Los Angeles (PST)!

Next I wanted to figure out what this TZ= value was and how to display the time zones I’d chosen. I decided to display time zones for PST, CST, EST, London, Berlin, India, and Japan. The next challenge was finding out what this ‘America/Los_angeles’ syntax was and where to find the other time zones.

Back to our man page: > ENVIRONMENT > TZ Specifies the time zone, unless overridden by command line parameters. If neither is specified, the setting from /etc/localtime is used.

$ ls -la /etc/localtime
 lrwxrwxrwx. 1 root root 35 Sep  4 17:23 /etc/localtime -> ../usr/share/zoneinfo/Europe/London
$ man 5 localtime | grep etc
    /etc/localtime -> ../usr/share/zoneinfo/...
    The /etc/localtime file configures the system-wide time zone of the local system that is used by
    Because the time zone identifier is extracted from the symlink target name of /etc/localtime, this file
$ ls /usr/share/zoneinfo
Africa      Brazil   Egypt    GB-Eire    HST          Japan      Navajo    posixrules  Turkey     zone.tab
America     Canada   Eire     GMT        Iceland      Kwajalein  NZ        PRC         UCT        Zulu
Antarctica  CET      EST      GMT0       Indian       Libya      NZ-CHAT   PST8PDT     Universal
Arctic      Chile    EST5EDT  GMT-0      Iran         MET        Pacific   right       US
Asia        CST6CDT  Etc      GMT+0      iso3166.tab  Mexico     Poland    ROC         UTC
Atlantic    Cuba     Europe   Greenwich  Israel       MST        Portugal  ROK         WET
Australia   EET      GB       Hongkong   Jamaica      MST7MDT    posix     Singapore   W-SU

Jackpot! With a combination of man pages and exploration I found the directory where all of the time zone references lived.

The time zones I cared about ended up being:

zones=( \
    "US/Pacific" \
    "US/Central" \
    "US/Eastern" \
    "GMT" \
    "Europe/Berlin" \
    "Asia/Kolkata" \

Now it was a matter of iterating through the array and printing out each time zone.

for i in "${zones[@]}"; do
    if [ $(uname) == "Darwin" ]; then
        TZ="${i}" gdate
        TZ="${i}" date

Finally, I needed to add the part that I actually found useful… figuring out the date in the future for scheduling a meeting! The –date= flag ended up being the correct method, but I found the documentation of the syntax confusing. Eventually I stumbled upon the gnu.org documentation and it contains the best examples. Just append –date=“${1}” to our conditional above and we have a basic time zone display for any dates we specify!

$ ./test.sh now
Sun Mar 05 14:51 PST -0800
Sun Mar 05 16:51 CST -0600
Sun Mar 05 17:51 EST -0500
Sun Mar 05 22:51 GMT +0000
Sun Mar 05 23:51 CET +0100
Mon Mar 06 04:21 IST +0530
Mon Mar 06 07:51 JST +0900
$ ./test.sh "2 days 2 hour"
Tue Mar 07 16:51 PST -0800
Tue Mar 07 18:51 CST -0600
Tue Mar 07 19:51 EST -0500
Wed Mar 08 00:51 GMT +0000
Wed Mar 08 01:51 CET +0100
Wed Mar 08 06:21 IST +0530
Wed Mar 08 09:51 JST +0900
$ ./test.sh "1 days 8 hour"
Mon Mar 06 22:51 PST -0800
Tue Mar 07 00:51 CST -0600
Tue Mar 07 01:51 EST -0500
Tue Mar 07 06:51 GMT +0000
Tue Mar 07 07:51 CET +0100
Tue Mar 07 12:21 IST +0530
Tue Mar 07 15:51 JST +0900

Overall I am happy with the result, but I was not expecting it to be quite as involved as it was. I found the documentation in date somewhat confusing, especially once you get into the date formating and also the implementation differences between distributions. I could not use this command easily without referencing the man page each time, so I guess a script makes the most sense!

I’m adding a few more bells to it and plan to add a whistle or two later on. You can follow my progress at https://github.com/whatupmiked/tzdate.