JavaScriptSerializer UTC DateTime问题

我们的客户希望在浏览器中显示日期和时间值,完全像它们在数据库中一样,并且我们将它们作为UTC存储在数据库中。

起初,我们在序列化和Javascript方面遇到了一些问题。 DateTime值被移位两次 - 首先匹配机器的本地时区,然后匹配浏览器中的时区。 我们通过向JavaScriptSerializer添加自定义Converter来修复它。 我们将DateTime标记为Serialize覆盖中的DateTimeKind.Utc。 将数据从Serialize中反馈出来有点困难,但我们发现了一些Uri hack,这有助于以相同的JavaScriptSerializer / Date(286769410010)/格式返回DateTime值,但不会转移到本地时间。 在Javascript方面,我们修补了KendoUI JS库以抵消构建的Date()对象,使它们看起来好像它们是UTC。

然后我们开始在另一边工作,反序列化。 同样,我们必须调整我们的代码,以使用自定义字符串替代JSON.stringify,它在从本地时间转换为UTC时再次抵消数据。 到目前为止,一切都很好。

但看看这个测试:

    public void DeserialiseDatesTest()
    {
        var dateExpected = new DateTime(1979, 2, 2,
            2, 10, 10, 10, DateTimeKind.Utc);

        // this how the Dates look like after serializing
        // anothe issue, unrelated to the core problem, is that the "" might get stripped out when dates come back from the browser
        // so I have to add missing "" or else Deserialize will break
        string s = ""/Date(286769410010)/"";

        // this get deserialized to UTC date by default
        JavaScriptSerializer js = new JavaScriptSerializer();

        var dateActual = js.Deserialize<DateTime>(s);
        Assert.AreEqual(dateExpected, dateActual);
        Assert.AreEqual(DateTimeKind.Utc, dateActual.Kind);

        // but some Javascript components (like KendoUI) sometimes use JSON.stringify 
        // for Javascript Date() object, thus producing the following:
        s = ""1979-02-02T02:10:10Z"";

        dateActual = js.Deserialize<DateTime>(s);
        // If your local computer time is not UTC, this will FAIL!
        Assert.AreEqual(dateExpected, dateActual);

        // and the following fails always
        Assert.AreEqual(DateTimeKind.Utc, dateActual.Kind); 
    }

为什么JavaScriptSerializer会反序列化/Date(286769410010)/ strings到UTC时间,但是1979-02-02T02:10:10Z到当地时间?

我们尝试将Deserialize方法添加到我们的自定义JavascriptConverter但问题是如果我们的JavascriptConverter具有以下类型,则不会调用Deserialize:

    public override IEnumerable<Type> SupportedTypes
    {
        get { return new List<Type>() { typeof(DateTime), typeof(DateTime?) }; }
    }

我想,仅当SupportedTypes包含一些具有DateTime字段的复杂实体的类型时才会调用Deserialize。

所以, JavaScriptSerializerJavascriptConverter有两个不一致之处:

  • Serialize为每个数据项都考虑了SupportedTypes中的简单类型,但反序列化忽略了它对于简单类型的类型
  • 反序列化将某些日期反序列化为UTC,还有一些日期为当地时间。
  • 有没有简单的方法来解决这些问题? 我们有点害怕用其他序列化程序代替JavaScriptSerializer ,因为我们正在使用的一些第三方库依赖于JavaScriptSerializer某些“功能/错误”。


    JavaScriptSerializerDataContractJsonSerializer充满了bug。 改用json.net。 即使是微软已经在ASP.Net MVC4和其他最近的项目中进行了这种转换。

    /Date(286769410010)/格式是专有的,由Microsoft组成。 它有问题,并没有得到广泛的支持。 你应该使用1979-02-02T02:10:10Z格式。 这在ISO8601和RF3339中定义。 它既是机器也是人的可读性,词汇排序,文化不变和明确。

    在JavaScript中,如果您可以保证您将在较新的浏览器上运行,请使用:

    date.toISOString()
    

    在这里引用。

    如果您想要完整的跨浏览器和较老的浏览器支持,请改用moment.js。

    UPDATE

    顺便说一句,如果你真的想继续使用JavaScriptSerializer ,你可以反序列化到一个DateTimeOffset ,这将保留正确的时间。 您可以从那里获取UTC DateTime时间,如下所示:

    // note, you were missing the milliseconds in your example, I added them here.
    s = ""1979-02-02T02:10:10.010Z"";
    
    dateActual = js.Deserialize<DateTimeOffset>(s).UtcDateTime;
    

    你的测试现在会通过。

    链接地址: http://www.djcxy.com/p/8141.html

    上一篇: JavaScriptSerializer UTC DateTime issues

    下一篇: How to assume local time zone when parsing ISO 8601 date string?