The fourth article in the small-and-sweet functions series introduces a function called datestamp()
, which uses various JavaScript Date
methods to produce a UTC date-string in the ISO 8601 format, like “1991-08-06T08:30:00Z”.
The ISO 8601 format is an incredibly robust and ubiquitous way of representing dates. It’s the format of choice for many other standards and specifications because it ticks so many boxes:
- It stores a complete date and time, providing all the necessary raw information to create any other format.
- It has explicit delimiters, no internal whitespace, and is always a constant length – all of which make it easy, cheap, and unambiguous to parse.
- It can be used in many language-specific date constructs, such as the input to a JavaScript
Date
object, or the value in a SQLDATESTAMP
column. - It falls into chronological order if sorted alphabetically.
- It is produced automatically when a JavaScript
Date
object is passed toJSON.stringify()
. - It is the format and profile recommended by the W3C.
- It is used in the HTML5
"datetime"
input.
The datestamp
function is a handy abstraction for creating this format, and works in even the most basic of JavaScript browsers. Here’s the code:
function datestamp(date)
{
if(isNaN((date = typeof(date) !== 'undefined' ? new Date(date) : new Date()).getTime()))
{
return null;
}
var pad2 = function(n) {
return (n < 10 ? '0' : '') + n;
},
tokens = [[['FullYear'], ['Month', 1], ['Date']], [['Hours'], ['Minutes'], ['Seconds']]];
for(var a = tokens.length, i = 0; i < a; i ++)
{
for(var b = tokens[i].length, j = 0; j < b; j ++)
{
tokens[i][j] = pad2(date['getUTC' + tokens[i][j][0]]() + (tokens[i][j][1] || 0));
}
}
return tokens[0].join('-') + 'T' + tokens[1].join(':') + 'Z';
}
How the Function Works
The function can create a brand new date, or it can start with any input date that’s supported by JavaScript’s Date()
constructor. Examples of supported formats are Unix timestamps, ISO datestamps, and existing Date
objects. The following example shows datestamp()
in action. Note that partial dates such as "1991-08-06"
should be avoided, because browsers vary in what they’ll assume the time to be.
datestamp();
datestamp(1333880482000);
datestamp("Mon, 07 Feb 2000 09:22:04 GMT");
datestamp("Sun, 06 Feb 2000 23:22:04 +10:00");
datestamp("1973-05-29T03:03:45Z");
datestamp(new Date(1349646120000));
If the input isn’t valid, then the function returns null
. Otherwise, a Date
object is created and formatted using various UTC-specific methods, such as getUTCFullYear()
and getUTCDate()
. You can see how the tokens
array initially stores a set of references to these functions, and the iterative code uses those references to create each method name, like Minutes
for getUTCMinutes()
; the method is called, then the value it returns overwrites the original reference.
The definition for Month
also specifies a numeric increment – ["Month", 1]
rather than simply ["Month"]
. This is because the getUTCMonth()
method returns numbers between 0
and 11
, whereas months in the ISO format must be from 1
to 12
(or rather, from "01"
to "12"
).
Keeping the tokens in arrays isn’t specifically necessary, it’s just very handy. Doing so means we can keep the code size down by building method calls on the fly, and then compile the bulk of the datestamp with just a couple of join()
calls.
Universal is Best!
The datestamp()
function only creates dates as UTC, because they’re intended for programatic use, rather than human-readable output (although, as programatic formats go, it is eminently readable!). It’s also unnecessary and potentially confusing to store dates and times in different timezones – it’s simplest to always store them as UTC. That way, you have a common frame of reference for comparing and evaluating them, without losing any information that’s need for internationalization.
When it comes time to actually display dates and times in the user’s browser, convert them to a friendlier local format. JavaScript is particularly handy for this because it evaluates on the client, using their clock. So, any timestamp passed through the Date()
constructor is automatically converted to the user’s locale (unless you use the getUTC
methods, as we do in this function). Taking a UTC datestamp in the ISO format, and converting it to a human-friendly and locale-specific date, can be as simple as this:
new Date("1991-08-06T08:30:00Z").toString();
Conclusion
The ISO 8601 format is arguably the most useful format for storing dates. But, it does have one slight drawback, in the fact that some older browsers don’t support it as the input to the Date()
constructor. These browsers include Safari 3 and Internet Explorer 8 or earlier. So, for the very next article in this short-and-sweet functions series, I’ll be showing you a reciprocal function that parses ISO datestamps to produce a Unix timestamp – something that even IE6 can understand!
James is a freelance web developer based in the UK, specialising in JavaScript application development and building accessible websites. With more than a decade's professional experience, he is a published author, a frequent blogger and speaker, and an outspoken advocate of standards-based development.