On the nightmare that is JSON Dates. Plus, JSON.NET and ASP.NET Web API
Ints are easy. Strings are mostly easy. Dates? A nightmare. They always will be. There's different calendars, different formats. Did you know it's 2004 in the Ethiopian Calendar? Yakatit 26, 2004, in fact. I spoke to a German friend once about how much 9/11 affected me and he said, "yes, November 9th was an amazing day in Germany, also."
Dates are hard.
If I take a simple model:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class Post{ public int ID { get; set; } [StringLength(60)][Required] public string Title { get; set; } [StringLength(500)] [DataType(DataType.MultilineText)] [AllowHtml] public string Text { get; set; } public DateTime PublishedAt { get; set; }} |
And I make a quick ASP.NET Web API controller from VS11 Beta (snipped some stuff for simplicity):
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class PostAPIController : ApiController{ private BlogContext db = new BlogContext(); // GET /api/post public IEnumerable<Post> Get() { return db.Posts.ToList(); } // GET /api/post/5 public Post Get(int id) { return db.Posts.Where(p => p.ID == id).Single(); } ...snip...} |
And hit /api/post with this Knockout View Model and jQuery.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
$(function () { $("#getPosts").click(function () { // We're using a Knockout model. This clears out the existing posts. viewModel.posts([]); $.get('/api/PostAPI', function (data) { // Update the Knockout model (and thus the UI) // with the posts received back // from the Web API call. viewModel.posts(data); }); }); viewModel = { posts: ko.observableArray([]) }; ko.applyBindings(viewModel);}); |
And this super basic template:
|
1
2
3
4
5
6
7
8
9
10
11
|
<li class="comment"> <header> <div class="info"> <strong><span data-bind="text: Title"></span></strong> </div> </header> <div class="body"> <p data-bind="date: PublishedAt"></p> <p data-bind="text: Text"></p> </div></li> |
I am saddened as the date binding doesn't work, because the date was serialized by default like this. Here's the JSON on the wire.
|
1
2
3
4
5
6
7
8
9
10
11
|
[{ "ID": 1, "PublishedAt": "\/Date(1330848000000-0800)\/", "Text": "Best blog post ever", "Title": "Magical Title"}, { "ID": 2, "PublishedAt": "\/Date(1320825600000-0800)\/", "Text": "No, really", "Title": "You rock"}] |
Eek! My eyes! That's milliseconds since the beginning of the Unix Epoch WITH a TimeZone. So, converting in PowerShell looks like:
PS C:\> (new-object DateTime(1970,1,1,0,0,0,0)).AddMilliseconds(1330848000000).AddHours(-8) Sunday, March 04, 2012 12:00:00 AM
Yuck. Regardless, it doesn't bind with KnockoutJS either. I could add a bindingHandler for dates like this:
|
1
2
3
4
5
6
7
8
9
10
|
ko.bindingHandlers.date = { init: function (element, valueAccessor, allBindingsAccessor, viewModel) { var jsonDate = valueAccessor(); var value = new Date(parseInt(jsonDate.substr(6))); var ret = value.getMonth() + 1 + "/" + value.getDate() + "/" + value.getFullYear(); element.innerHTML = ret; }, update: function (element, valueAccessor, allBindingsAccessor, viewModel) { }}; |
That works, but it's horrible and I hate myself. It's lousy parsing and it doesn't even take the TimeZone into consideration. This is a silly format for a date to be in on the wire.

I was talking to some folks on Twitter in the last few days and said that all this is silly and JSON dates should be ISO 8601, and we should all move on. James Newton-King the author of JSON.NET answered by making ISO 8601 the default in his library. We on the web team will be including JSON.NET as the default JSON Serializer in Web API when it releases, so that'll be nice.
I mentioned this to Raffi from Twitter a few weeks back and he agreeds. He tweeted back to me
@shanselman if (when) we ship a v2 API, you can almost bet its going to be 8601 /cc @twitterAPI @johnsheehan
— Raffi Krikorian (@raffi) March 4, 2012
He also added "please don't do what the @twitterAPI does (ruby strings)." What does that look like? Well, see for yourself: https://www.twitter.com/statuses/public_timeline.json in a random public timeline tweet...snipped out the boring stuff...
|
1
2
3
4
5
6
7
8
9
10
|
{ "id_str": "176815815037952000", "user": { "id": 455349633,...snip... "time_zone": null }, "id": 176815815037952000, "created_at": "Mon Mar 05 23:45:50 +0000 2012"} |
Yes, so DON'T do it that way. Let's just do it the JavaScript 1.8.5/ECMASCript 5th way and stop talking about it. Here's Firefox, Chrome and IE.
![]()
We're going to do this by default in ASP.NET Web API when it releases. (We aren't doing this now in Beta) You can see how to swap out the serializer to JSON.NET on Henrik's blog. You can also check out the Thinktecture.Web.Http convenience methods that bundles some useful methods for ASP.NET Web API.
Today with the Beta, I just need to update my global.asax and swap out the JSON Formatter like this (see Henrik's blog for the full code):
|
1
2
3
4
|
// Create Json.Net formatter serializing DateTime using the ISO 8601 formatJsonSerializerSettings serializerSettings = new JsonSerializerSettings();serializerSettings.Converters.Add(new IsoDateTimeConverter());GlobalConfiguration.Configuration.Formatters[0] = new JsonNetFormatter(serializerSettings); |
When we ship, none of this will be needed as it should be the default which is much nicer. JSON.NET will be the default serializer AND Web API will use ISO 8601 on the wire as the default date format for JSON APIs.

Hope this helps.
On the nightmare that is JSON Dates. Plus, JSON.NET and ASP.NET Web API的更多相关文章
- Replace JSON.NET with ServiceStack.Text in ASP.NET Web API
Because ServiceStack.Text performs much better I recently stumbled across a comparison of JSON seria ...
- ASP.NET WEB API 返回JSON 出现2个双引号问题
前言 在使用ASP.NET WEB API时,我想在某个方法返回JSON格式的数据,于是首先想到的就是手动构建JSON字符串,如:"{\"result\" ...
- 【ASP.NET Web API教程】6.2 ASP.NET Web API中的JSON和XML序列化
谨以此文感谢关注此系列文章的园友!前段时间本以为此系列文章已没多少人关注,而不打算继续下去了.因为文章贴出来之后,看的人似乎不多,也很少有人对这些文章发表评论,而且几乎无人给予“推荐”.但前几天有人询 ...
- Asp.Net Web API 2第十三课——ASP.NET Web API中的JSON和XML序列化
前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok/p/3446289.html 本文描述ASP.NET W ...
- ASP.NET Web API中的JSON和XML序列化
ASP.NET Web API中的JSON和XML序列化 前言 阅读本文之前,您也可以到Asp.Net Web API 2 系列导航进行查看 http://www.cnblogs.com/aehyok ...
- ASP.NET Web API 2.1支持Binary JSON(Bson)
ASP.NET Web API 2.1内建支持XML.Json.Bson.form-urlencoded的MiME type,今天重点介绍下Bson.BSON是由10gen开发的一个数据格式,目前主要 ...
- 使用Jil序列化JSON提升Asp.net web api 性能
JSON序列化无疑是Asp.net web api 里面性能提升最重要的一环. 在Asp.net web api 里面我们可以插入自定义的MediaTypeFormatter(媒体格式化器), 说白了 ...
- ASP.NET Web API 如何通过程序控制返回xml还是json
雖然 ASP.NET Web API 內建支援 JSON 與 XML 兩種輸出格式,並依據瀏覽器端送出的 Accept 標頭自動決定回應的內容格式,不過有時候我們的確也需要讓程式來控制要回應哪種格式, ...
- 解决ASP.NET Web API Json对象循环参考错误
前言 一般我们在开法 ASP.NET Web API 时,如果是使用 Entity Framework 技术来操作数据库的话,当两个 Entity 之间包含导览属性(Navigation Proper ...
随机推荐
- 向HDFS中追加内容
向生成好的hdfs文件中追加内容,但是线上使用的版本是1.0.3,查看官方文档发现,在1.0.4版本以后才支持文件append 以下是向hdfs中追加信息的操作方法 如果你只在某一个driver中追加 ...
- ①SpringBoot入门教学篇
一.什么是spring boot Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置,从而使开发 ...
- 64位linux下rpm安装mysql的5.5.55版本
昨天同事开了个阿里云环境,让我帮他安装mysql数据库,本想着很简单的一件事,结果还是折腾了一番.坑很多,一路趟过,一个接一个,只能硬着头皮冲. 首先是下载压缩包,因为采用了rpm安装方式,所以下载的 ...
- RHEL6.2配置从零开始
RHEL6.2最小化安装并配置,持续更新中... 1.RHEL6.2最小化安装 RHEL6.2默认安装许多用不到的软件,不仅浪费空间.增大系统开销,还会显得凌乱.所以选择最小化安装. 注意:安装步骤 ...
- java成神之——Fork/Join基本使用
Fork/Join 大任务分小任务,小任务结果合并 ForkJoinPool pool = new ForkJoinPool(); RecursiveTask<Integer> task1 ...
- 第七章 AOP(待续)
···············
- flask系列一之环境搭建包安装
一,python的安装 (1)python的安装 (2)虚拟环境的配置 参考:http://www.cnblogs.com/bfwbfw/p/7995245.html 1,虚拟环境的建立 (1)使用p ...
- HTML5+ 初识,HBuilder,夜神模拟器,Webview
一.HTML5+ 初识 HTML5 Plus应用概述 HTML5 Plus移动App,简称5+App,是一种基于HTML.JS.CSS编写的运行于手机端的App,这种App可以通过扩展的JS API任 ...
- day16-作业 后台管理
二话不说开撸作业 作业要求: 后台管理平台 ,编辑表格:1. 非编辑模式:可对每行进行选择: 反选: 取消选择2. 编辑模式:进入编辑模式时如果行被选中,则被选中的行万变为可编辑状态,未选中的不改变退 ...
- Djano + Nginx + docker配置与管理
在配置这个服务之前,应该对docker的基本安装与使用应该很熟悉了.下面开始直接不如正题 1.让我们创建一个名为myproject的空目录,并在src名称内添加另一个文件夹.src应该包含django ...