3

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?

99miles
  • 10,942
  • 18
  • 78
  • 123
  • 1
    See http://stackoverflow.com/questions/2479714/does-javascript-ecmascript3-support-iso8601-date-parsing – Crescent Fresh Mar 26 '10 at 19:34
  • Thanks, but I'm not finding anything there that works, or does what I want. The only thing that seems to work is 'Yet Another Pretty Date JavaScript', but it just returns stuff like '2 days ago', which isn't the info I'm looking for. – 99miles Mar 26 '10 at 19:53
  • 1
    before you can format, first you parse (which is what that link illustrates). – Crescent Fresh Mar 27 '10 at 00:13

3 Answers3

2

Why not just pass it as a timestamp rather than a date and multiply by 1000?

new Date( ruby_val * 1000 );
zackrw
  • 21
  • 2
  • I think this makes a lot more sense. Override `as_json` on your Rails model to output the unix time stamp and on the client side just create a date object from unix time stamp. – Sherwin Yu Aug 30 '12 at 04:54
2

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
  • 28,815
  • 8
  • 42
  • 39
1

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
  • 2,531
  • 1
  • 17
  • 22
  • 1
    (-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 Mar 27 '10 at 01:04
  • 1
    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 Mar 27 '10 at 01:14
  • +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 Mar 27 '10 at 03:23
  • 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 Mar 29 '10 at 23:43
  • @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 Mar 30 '10 at 06:44
  • 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 Mar 30 '10 at 15:21