Leap seconds and Datefudge
Time can be a pretty tricky thing for programs to manage. In fact there is a long list of time related bugs on Wikipedia. Dealing with time is tricky for a several of reasons.
Countries use one (or more) time zones, however time zones
are not always straightforward. For example did you know that Indian standard
5:30 ahead of UTC?
Time zones also regularly change, for example the most recent changes made to
tzdata package on CentOS are:
* Wed Nov 23 2016 Patsy Franklin <[email protected]> - 2016j-1 - Rebase to tzdata-2016ij - Saratov region of Russia is moving from +03 offset to +04 offset on 2016-12-04. * Wed Nov 02 2016 Patsy Franklin <[email protected]> - 2016i-1 - Rebase to tzdata-2016i: - Cyprus is now split into two time zones as of 2016-10-30 - Tonga will reintroduce DST on 2016-11-06
Daylight savings time
At the time of writing just over seventy countries use daylight savings time. This can result in some interesting logs similar to the following:
[1:55:47] INFO some message before the clocks went back [1:02:22] INFO a message after the clocks went back
The speed the earth rotates at isn't constant, as a result leap seconds have periodically been added to UTC, most recently at the end of 2016. To make matters worse, leap seconds are irregularly spaced due to the irregularity of the Earth's rotation.
Testing with datefudge
datefudge is a great tool for testing time based bugs. On CentOS 7 it can be installed from EPEL:
yum install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm yum install -y datefudge
Once datefudge is installed, it can be used to simulate running a program at a different time. For example if you want to simulate running a program while the while the clocks change in the UK you could do the following:
$ datefudge 2016-10-30T00:59:58z bash -c 'while true; do date; sleep 1; done' Sun 30 Oct 01:59:58 BST 2016 Sun 30 Oct 01:59:59 BST 2016 Sun 30 Oct 01:00:00 GMT 2016 Sun 30 Oct 01:00:01 GMT 2016
--static option can also be used to freeze time for the application:
$ datefudge --static 2016-10-30T00:59:58z bash -c 'while true; do date; sleep 1; done' Sun 30 Oct 01:59:58 BST 2016 Sun 30 Oct 01:59:58 BST 2016 Sun 30 Oct 01:59:58 BST 2016
You can also watch last year's leap second being added:
$ datefudge 2016-12-31T23:59:58z bash -c 'while true; do date; sleep 1; done' Sat 31 Dec 23:59:58 GMT 2016 Sat 31 Dec 23:59:59 GMT 2016 Sat 31 Dec 23:59:60 GMT 2016 Sun 1 Jan 00:00:00 GMT 2017 Sun 1 Jan 00:00:01 GMT 2017
Note: the default set of CentOS time zone files do not correct for leap
seconds. To replicate the behaviour above you can copy
/etc/localtime as described in
Red Hat solution 2441291.