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 format
JsonSerializerSettings 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.

最新文章

  1. 第三方开源库和jar包的区别
  2. SQL 从指定表筛选指定行信息 获取表行数
  3. Java批量文件打包下载
  4. Android Studio Gradle 问题 解决方案
  5. Last non-zero Digit in N!(阶乘最后非0位)
  6. 关注经典:CSS Awards 获奖网站作品赏析《第一季》
  7. 线程本地存储TLS(Thread Local Storage)的原理和实现&mdash;&mdash;分类和原理
  8. HTML5-常见的事件- beforeunload事件
  9. 国内三大PTPrivate Tracker站分析
  10. arcgis api 3.x for js 入门开发系列十八风向流动图(附源码下载)
  11. 如何连接别人电脑上的Oracle数据库?
  12. tcpdump抓包常用命令列举
  13. 20175224 2018-2019-2 《Java程序设计》第四周学习总结
  14. python 学习第一天
  15. Android apk动态加载机制
  16. vue2.0 vs vue
  17. Java并发知识整理
  18. 《A_Pancers》第一次作业:团队亮相
  19. 20145204《java程序设计》课程总结
  20. 最短路径算法(I)

热门文章

  1. flask 之 mongodb
  2. 今天去python官网下载包安装的时候的问题记录
  3. Avro之一:Avro简介
  4. mysql实战优化之四:mysql索引优化
  5. spring bean id重复覆盖的问题解决
  6. 【原创】 HBase 配置指南
  7. sublime text3 FTP直接上传
  8. ServiceWorker入门介绍一
  9. Oracle 复杂查询(1)
  10. mysql字符类型