It's astounding, time is fleeting, madness takes its toll, ...

Okay, starting a blog post using a title from the first lines of the lyrics to "The Time Warp" does seem a bit unusual but with what I intend to cover in this it will all make sense, probably.

Time... what is it really? I am not going into some weird arty-pseudo-psycho babble of the ephemeral nature of time but as a software developer I usually have to deal with time, and dates, in some form everyday and I find myself having the same conversations with other developers about how to handle date and time in specific scenarios. What I have found is that even though we, as people, use time every day in our lives we really don't always understand it and even when we feel we have a grasp we often have to remind ourselves about what we are doing. Even now when someone refers to something like "midnight on the 20th", I have to query "Do you mean the midnight between the 19th and 20th or the 20th and 21st?"; people usually mean the latter but for computers it is always the former. Now, the observant amongst you may have noticed that I started off with 'time' but now I have started to use the terms 'date and time' together and that is very deliberate as time on its own is pretty useless for most cases without the date and together they create the when. And now I am going to add a third term to the mix and this is where because date and time we observe in the real-world is also dependant on where you are and I think anyone reading this will have experienced this at some point.

My rules

I am not going to say my grasp on the subject is perfect, as obvious from above, and to help developers like myself there are some wonderful libraries that really take the grunt work out of the handling of date and time but even with these tools we can still mess it up because we forget about what it is we are trying to handle. Personally, when it comes to development I have a few simple rules that pretty well cover 99% of all cases that I have to deal with when handling date and time that I would like to share.

Rule 1: If in doubt, make sure you use UTC...

... and make it someone else's problem to convert it; this is pretty well my default position on most occasions when I need to deal with time.

UTC stands for Coordinated Universal Time and if you are confused about about the abbreviation well it was apparently chosen so that it does not favour any one language.

But regardless of the abbreviation employed it is an awesome thing for us developers as it gives us a common baseline that can be utilised by the languages we use in our daily development; it is unlikely that you will find a modern language that does not support some way of getting the current date and time in UTC e.g.

  • JavaScript: var when = Date.now();
  • .NET: var when = DateTime.UtcNow;

UTC is great for logging and auditing purposes, and really anytime we want to store a time-stamp against a specific piece of data or an event. Even better for computers, as long as they are correctly sync'd to a time server, then the UTC time you will get on each computer will be the same (I am ignoring things like clock-drift etc for this article but I acknowledge its existence and the issues it can cause). Finally UTC isn't affected by DST and so you don't get odd behaviour due to time when this local time change occurs.

DST stands for Daylight Savings Time and its application around the world is rather arbitrary with some countries adopting it, others ignoring and some using it, applying it all year round, abandoning it. And in some cases like Australia it depends on the state.

UTC is also great for storing past events because, the past doesn't change and so converting it to local time for a viewer is always predictable; this is where those libraries really come in useful as they can also take care of that oft-forgotten DST offset that sometimes needs to be applied as well as the users timezone (the when and the where aspects) when you need to present the time of the event back to the user.

Learn to read time

Most languages support the basics of dealing with dates and time but it is also good to make sure you also understand how to interpret some common time representations.

  • "2017-02-05 05:00:00" - 5am on 5th February 2017, however there is no timezone information and so will, more often than not, be interpreted as local time by most languages.
  • "2017-02-05 05:00:00Z" - 5am on 5th February 2017 UTC, the Z indicates what is known as Zulu time and is another, usually military/aviation, term for UTC.
  • "2017-02-05 05:00:00+00:00" - is also 5am on 5th February 2017 UTC, this time we have provided the offset in hours and minutes from UTC that the time represents.
  • "2017-02-05 05:00:00+11:00" - is also 5am on 5th February 2017 but this time in a timezone that is currently 11 hours ahead of UTC; this is equivalent to "2017-02-04 18:00:00+00:00".
  • "2017-02-05 05:00:00-07:00" - is also 5am on 5th February 2017, in a timezone that is currently 7 hours behind UTC; this is equivalent to "2017-02-05 12:00:00+00:00".
  • "2017-02-05T05:00:00+1100" - is also 5am on 5th February 2017, in a timezone that is currently 11 hours ahead of UTC; this is a common representation often seen, a T is used to separate the date and time and the offset is still hours and minutes but they are sometimes not separated by a colon (:); in this case however if the the offset is missing then assume UTC(*).

(*) “Your "common representation often seen" is ISO 8601. This is the universal standard. A pox on all those framework designers who bastardised it slightly because reasons...”
- I Shepherd

ISO 8601https://xkcd.com/1179/

If you do see a time stamp with an offset e.g. +11:00 or -07:00, then to convert it back to UTC you subtract the hours and minutes from the time presented, as shown in the above examples; please note that you should treat the +/- sign as you would in any addition operation.

Learn to write and parse time

Though reading time seems pretty straightforward for us humans, for computers it can be quite tricky because us humans are not sensible/consistent and some libraries don't default the way you would think they would e.g. 01/02/2017 is this Jan 2nd or Feb 1st, depending on where you are from will probably determine what you say; if you are US American then you will probably go with the former but the rest of the world will more likely go with the latter (exceptions apply). But what about computer libraries what will they do?

// Wed Feb 01 2017
console.log(new Date(Date.parse('2017/2/1')).toString());

// Mon Jan 02 2017
console.log(new Date(Date.parse('1/2/2017')).toString());

// Invalid Date
console.log(new Date(Date.parse('13/2/2017')).toString());  

So we see that default parsing in JavaScript will assume that if you put a year first then it will be followed by month and then date but it will assume US American format if you put the year at the end. So my rule of thumb here is to always format dates as year/month/day and if I have to parse a date format that I didn't write myself to ask about the format used because you may need to work just a little bit harder when you parse it.

Rule 2: For real-life events, store the timezone...

... of where the event is expected to take place. This will then allow you to convert the stored time to another local time in another timezone. This is really important for events that are to happen in the future because the future is fluid and it is not unknown for some countries to change when they may trigger daylight savings with extremely short notice but if you keep your computer patched with the updates then you should be okay i.e. if you are on a Microsoft OS then KB914387 is the one to keep any eye on; you may find it quiet interesting to see what changes have happened around the world.

Now you may have noticed that I haven't said anything about whether the date and time of the event should be stored in UTC or local time and that is because it depends on your scenario.

Example 1 - TV Schedule. The "Local News at 6pm" will, more often than not, be scheduled at 6pm and this will happen day after day regardless of the DST in effect, even if DST usage was suddenly changed. In this scenario storing the local date and time along with the timezone is probably fine. The same would apply for any sort of events that stop and start in the same location e.g. meetings, restaurant bookings etc. You may even find that the timezone is largely unused if the event is just physical but if there is any electronic sharing of the booking to persons or systems outside the location then it is usually important to maintain the timezone component.

Example 2 - Travel. Events like travel where the start time and end time could possibly be in different times zones e.g. Air travel, then storing the date and time in UTC along with the timezone(s) will probably be the best approach. The complexity involved in planning flights etc would not adapt quickly to a sudden change in DST usage and so the people affected may just find that the local time of the flight has changed but not as it relates to the rest of the world.

Which timezone list?

When storing your timezone try to store and use a library that will let you use the timezone list from the tz database, this list usually breaks a timezone into a region and place e.g. Europe/London or Australia/Melbourne, and tends to have more cross adoption between languages than other, usually OS specific, lists.

This list is also more granular and deal with the oddballs of the world e.g. in Australia for instance we have:

  • NSW (+10:00), VIC (+10:00), SA (+09:30), ACT (+10:00) and TAS (+10:00) all of which use DST but QLD (+10:00), NT (+9:30) and WA (+08:00) currently do not.
  • a town called Broken Hill (Yancowinna) that is in NSW (+10:00) but instead shares the same timezone as SA (+09:30) aka "Australia/Broken_Hill".
  • a town in WA (+08:00) called Eucla (+08:45) which is in a timezone that has a +45 minutes offset to the rest of the state aka "Australia/Eucla".
  • and (finally) and island off NSW (+10:00) call Lord Howe Island (+10:30) that utilises a +30 minute DST during summer.

It's not just the wildlife that makes Australia just one strange place.

Libraries

There are many libraries out there for your chosen language that will help you handle time especially if your chosen language has limited support. I'll only list ones that I have used recently that have done the job asked of them (and support the above timezone list) rather than discuss the merits of each library.

Rule 3: Avoid using "Local Now"...

... and instead use "UTC Now" whenever possible, especially when processing 2 or more times. "Local Now" is subject to the computer settings the code it is executed on and when the wrong "now" is used the defects are really subtle and may not be easily repeatable on a developers machine. If you are in

  • Europe/Africa: then the odds you will not notice the issues during your working day but your users may report odd things happening late at night.
  • North/South America: if anything is going to occur it will probably be during the afternoon when the weird stuff happens.
  • Asia/Australia: the system will probably have odd behaviour during the morning.

The issues usually arise because developers have their machines running in local time but it is not unusual nowadays for servers in the cloud to be running UTC (with no DST applied) and so if a developer uses "Local Now" they should really use "UTC Now" and convert it to the actual timezone. Personally I would ban any local now usage from my code base and I would like that Microsoft make methods/functions like DateTime.Now obsolete.

Testing

Testing your time manipulations and conversions can be very tricky especially if you use the System API to get the current time in your tests. If you can, try and mock out the usage of such APIs; some libraries such as NodaTime supply one for you, with JavaScript something like Sinon.JS may be your best bet. You may also find it worthwhile that when you run your tests that you change the timezone of you development environment occasionally and check that your tests continue to work regardless of the timezone of the computer running the tests. You may also find that you need to check your test data with an external system so I recommend the meeting planner on http://www.timeanddate.com as it allows you to enter your own times and see the results for multiple locations.

...finally

These are the rules I try to abide by but rules can be broken sometimes and there will always be special cases.

If you have further suggestions about what has worked for you that you would care to share, or see or believe that I have made a grave error in my thinking then please comment below, I am always willing to discuss and learn.

Other Resources

Falsehoods programmers believe about time - Infinite Undo!