views:

97

answers:

2

I'm passing a date from Ruby to Javascript via JSON.

It comes into Javascript as "2010-03-24T10:00:00Z".

Now, how the heck do I format that in Javascript?

+1  A: 

I suppose I'd do it kinda like this to construct a date object first:

function dp(dateStr) {
    var pattern = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})Z$/;
    var match = pattern.exec(dateStr);
    if (!match) {throw new Error('::Error, #dp could not parse dateStr '+dateStr);}
    // we're safe to use the fields
    return new Date(match[1], match[2]-1, match[3], match[4], match[5], match[6]);
}
console.log(dp('2010-03-24T10:00:00Z'));

Then I could pretty-print it in different ways. See how the month (field with idx 2 in the match array) needs to be fiddled with due to zero-index (as opposed to the date field).

npup
(-1) parsing a date with a regex is generally a bad idea. Its difficult to account for all the variations. Its best to usually leave it up to an API who has tackled the problem in earnest. See comment posted by @Crescent for a better alternative.
harschware
Eh? It was a pretty well defined task with a very well known format. The `Date.parse` function is not reliable either. There is not even anything in the standard that says it should work for a string like for example "2010-02-23T23:04:48Z". So we have regexes. Were it very much called for there are of course more checks to do (check bounds of each retrieved field for example).
npup
+1 @harschware date representation is a major problem as even standardized formats (RFC822, RFC3339, ..) include a high level of variability and dates are not usually accompanied by the spec that is being used to represent them, so it becomes utterly impossible to write a standardized date parser so we are basically left with trying various formats. The format in question is `ISO 8601`, which is rather standardized and I see no problems parsing it with a regex. regex is not evil.
Anurag
OK sure you can handle it with a regex, but my more important point was that you shouldn't try to re-invent the wheel if you can help it. Just look at @Fabian's post: it uses an API (json2), and that regex has clear differences from @npup's that show yours probably misses some important variations and doesn't account for timezone handling correctly. With that being the case I should let the downvote stand.
harschware
@harschware If one could rely on `Date.parse()` to do the job in all browsers I'd go for it. But that is not the case. Of course there is more checks (for constrains on date values and also timezone stuff as you mentioned) to do when you roll your own *to the fullest*. I didn't read the question here as "Make a full blown date parser that handles anything and all around the world" though, but " **How to format a date string in javascript** ". The **string**! And my approach was that the string was fine and I wanted to put it in a date just to make it easy to format it to my pleasing afterwards
npup
You make a good point. The OP has asked about formatting which at least you've addressed, even if the parsing aspect could be done better (or better yet using a pre-existing, well tested routine). The OP only asked about parsing indirectly, so I guess if there is an issue with the parsing its not really deserving of a down vote. I give ... :-)
harschware
+1  A: 

According to the EcmaScript 5 spec, JSON dates should be encoded as ISO strings. This is how toJSON of JavaScript date objects could look like:

function f(n) {
    // Format integers to have at least two digits.
    return n < 10 ? '0' + n : n;
}

Date.prototype.toJSON = function (key) {
  return isFinite(this.valueOf()) ?
    this.getUTCFullYear()   + '-' +
    f(this.getUTCMonth() + 1) + '-' +
    f(this.getUTCDate())      + 'T' +
    f(this.getUTCHours())     + ':' +
    f(this.getUTCMinutes())   + ':' +
    f(this.getUTCSeconds())   + 'Z' : null;
};

Fortunately Ruby seems to encode dates the same way. An elegant solution is to provide a reviver function to the JSON parse function, which converts ISO date strings into Date objects:

myData = JSON.parse(text, function (key, value) {
  var a;
  if (typeof value === 'string') {
    a = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2}(?:\.\d*)?)Z$/.exec(value);
    if (a) {
      return new Date(Date.UTC(+a[1], +a[2] - 1, +a[3], +a[4], +a[5], +a[6]));
    }
  }
  return value;
});

This should work with all standard compliant JSON implementations.

Both samples are taken from the json2 source code by Douglas Crockford.

Fabian Jakobs