Keith Cirkel

Software Cyber Shepherd

Start sending dates the right way (aka The ISO8601 101)

We’ve all had those tough conversations on how best to exchange dates between two systems: “is DD-MM-YYYY good for everyone?” “what about YYYY/MM/DD” “we could just use Epoch timestamps”…

Each option is rife with problems; some don’t convey enough info, some are too ambiguous, and others are hard on the human eye. Compounding these difficulties are the myriad of standards that work across different systems.

Luckily there is a solution, It is flexible, readable and unambiguous. ISO8601.

ISO8601 is simply the best standards to use. It can provide the maximum amount of info reasonably required when interchanging dates between systems. It can provide units all the way down to second decimals. It includes support for time zones and strictly specifies the order of each date fragment, all while still being reasonably terse. It looks something like this:

2012-05-04T12:20:34.000343+01:00

Let’s dissect ISO8601 at a deeper level and further prove why you should be using it.

Strict ordering

ISO8601 defines the exact order at which the date should be represented, in a system that is called “big endian” (smallest last). This means that the biggest unit comes first, followed by the next, all the way down to the smallest. It also says that the biggest unit needed is year, so ISO8601 dates have to be ordered as YYYY-MM-DD, times have to be ordered to HH:MM:SS, followed by an optional second decimal. This is great because not only is this completely unambiguous (you’ll never confuse MM for DD again) but it also makes it very easy to read (everything is in its expected place). It just makes sense.

Time zone support

It supports time zones, and it has a predefined way of doing so, like +HH:MM (or +HHMM). Date formats like Seconds-from-Epoch just cannot convey this and so - as well as being completely unreadable - they are not as well suited as ISO8601.

Send as much or as little as you need

Inherently ISO says you can optionally send as much data as you want to, and it still be a valid ISO string, so for example YYYY would be a valid ISO date, as would YYYY-MM, YYYY-MM-DDTHH. You can supply the time zone, or omit it, up to you. You can only omit going down though, so a date like MM-DD isn’t valid, because it is missing the year.

The downsides

The upshot of this flexibility though, and one that is pretty much universally missed by languages is that you can also do crazy stuff like provide seconds to as many decimal places as you want. So a date like 2009-09-09T09:09:09.00000000000000000009 is totally valid. ISO8601's biggest gain is also its biggest pain, which makes it very difficult to code a reliable parser for the standard. Some small but annoying quirks to look out for are:

Unlimited decimals allowed for seconds, The T separator between the date and time can be pretty much anything time zone can be omitted, or Z, it can have a : to separate hours from minutes, or not.

Of course all of this also means that different languages can and will do different stuff with ISO8601. For example languages like Python and .NET will use 6 decimal places (microseconds) for seconds, while languages like PHP and JavaScript will use 3. Python allows you to change the ‘T’ separator at your whim, and also by default will omit any time zone data, not even add a Z, meanwhile JavaScript and other languages will always use ‘T’ and if no time zone data is present, will use Z for the time zone. See how this can get pretty complex pretty quickly?

Intervals

An awesome but oft overlooked part of ISO8601 is intervals. For example you are making a calendar, and you have a meeting that lasts 2 hours on it, with ISO8601 intervals you can express this as a string format, rather than using something ghastly like seconds or milliseconds:

'P6Y4M4DT3H45M15S'

The nice thing about ISO intervals is that they are human readable, they are easy enough to parse, and they follow stricter standards. An ISO interval must start with a P, standing for Period. From there it is simply a number, followed by a unit-like designator, for example months are M and days are D. To separate time from dates, use a T - just like ISO date times.

Tempus.JS

In JavaScript, ISO8601 isn't supported in older browsers, and some of the finer details mentioned aren't well supported in newer browsers. Luckily Tempus JS, my JavaScript date library will mask most of this away for you (as of 0.2 at least!), so you won’t need to worry about any of these problems. Tempus has an intervals module that also supports awesome ISO8601 Intervals.

Start using ISO8601 today

If you're sending dates across systems, there really is no excuse not to be using ISO8601. Tempus will make it super easy. Try it and never revert to the bad old ways.

If you're already using ISO8601, spread the word! If have any tips for readers, or want to shout at me for because you are still hanging on to Epoch timestamps, then you can do so by tweeting me, @keithamus, on Twitter.