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.
Time zones
Countries use one (or more) time zones, however time zones
are not always straightforward. For example did you know that Indian standard
time is 5:30
ahead of UTC?
Time zones also regularly change, for example the most recent changes made to
the 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
Leap seconds
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
The --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
/usr/share/zoneinfo/right/Europe/London
to /etc/localtime
as described in
Red Hat solution 2441291.