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 $@
else
date $@
fi
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" \
"Asia/Singapore")
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
else
TZ="${i}" date
fi
done
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.