Yesterday we updated the datajs codebase to support DateTime and DateTimeOffset. Here are some development notes on this that may be interesting.
Recognizing DateTime and DateTimeOffset values
ATOM has a pretty straightforward representation for DateTime and DateTimeOffset, so it’s really a matter of recognizing these on the wire and parsing them / serializing them.
JSON uses a convention where /Date(nnn)/ is used, where nnn is the number of miliseconds as per the Date(number) constructor. On the wire, this is actually serialized as \/Date(nnn)\/. The catch is that those backslashes escape the forward slashes even though escaping is not required, so it makes it harder to mis-recognize a string as a date value. However because we use the browser JSON parser, we don’t get to see this escape mechanism and it’s very hard to produce, so currently the library produces the ATOM format that some implementations recognize (including the WCF Data Services one).
Now, in the ATOM case this is unambiguous, because the type information comes out of line in an XML attribute. But in the JSON case, someone could “poison” the data by passing in a value that looks like a Date format, so by default datajs won’t convert string values into Dates even if they look like they might be. This way if your page relies on string properties being strings and not something else, a malicious user can’t break your site.
There are two ways to have datajs produce Date objects for JSON responses:
- If you provide metadata, the library knows for certain what is and isn’t a date, and uses that information.
- If you don’t provide metadata, but you trust that the server won’t hand out “dangerous” date (or your page won’t have a problem with it), you can set the recognizeDates property to true in the OData.jsonHandler object.
Representing DateTime and DateTimeOffset values
Representing DateTime values is pretty straightforward – we just use a Date object. You can use the UTC methods to work with this value “from the wire”, or you can of course use the local values to adjust it to the local user’s timezone.
For DateTimeOffset, we use a Date object with the time adjusted to UTC so you can use the UTC APIs without worrying about the local timezone of the user, or again adjust it as necessary (and without the offset getting in the way). We annotate it with an __edmType field with the value “DateTimeOffset”, and we annotate the offset value in an __offset field. The whole thing round-trips, and you can play with the values as needed.