簡體   English   中英

json.net序列化/反序列化datetime'未指定'

[英]json.net serialization/deserialization of datetime 'unspecified'

在常規.net中,如果我們有一個具有DateTimeKind.Unspecified的時間如果我們轉換ToLocal - 它假定轉換時輸入日期是UTC。 如果我們轉換ToUniversal - 它假定轉換時輸入日期是本地的

但是,在JSON.Net中,如果我們在JSON.Net中的字符串日期未指定,它似乎沒有這個邏輯? 看看我下面的測試用例 - 我做錯了嗎? 或者這是設計? 或JSON.Net中的錯誤? 謝謝!

    // TODO: This Fails with output
    //      date string: "2014-06-02T21:00:00.0000000"
    //      date serialized: 2014-06-02T21:00:00.0000000Z
    //      Expected date and time to be <2014-06-03 04:00:00>, but found <2014-06-02 21:00:00>.
    [TestMethod]
    public void NEW_Should_deserialize_unspecified_datestring_to_utc_date()
    {
        string dateString = "\"2014-06-02T21:00:00.0000000\"";
        DateTime dateRaw = new DateTime(2014, 6, 2, 21, 0, 0, 0, DateTimeKind.Unspecified);
        DateTime dateRawAsUtc = new DateTime(2014, 6, 3, 4, 0, 0, 0, DateTimeKind.Utc);
        dateRawAsUtc.Should().Be(dateRaw.ToUniversalTime());

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
        settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
        DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, settings);                

        Console.WriteLine("date string: " + dateString);
        Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));

        dateSerialized.Kind.Should().Be(DateTimeKind.Utc); 
        dateSerialized.Should().Be(dateRaw.ToUniversalTime());
        dateSerialized.Should().Be(dateRawAsUtc);
    }

    // TODO: This Fails with output
    //      date string: "2014-06-02T21:00:00.0000000"
    //      date serialized: 2014-06-02T21:00:00.0000000-07:00
    //      Expected date and time to be <2014-06-02 14:00:00>, but found <2014-06-02 21:00:00>.
    [TestMethod]
    public void NEW_Should_deserialize_unspecified_datestring_to_local_date()
    {
        string dateString = "\"2014-06-02T21:00:00.0000000\"";
        DateTime dateRaw = new DateTime(2014, 6, 2, 21, 0, 0, 0, DateTimeKind.Unspecified);
        DateTime dateRawAsLocal = new DateTime(2014, 6, 2, 14, 0, 0, 0, DateTimeKind.Local);
        dateRawAsLocal.Should().Be(dateRaw.ToLocalTime());

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
        settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
        DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, settings);

        Console.WriteLine("date string: " + dateString);
        Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));

        dateSerialized.Kind.Should().Be(DateTimeKind.Local);
        dateSerialized.Should().Be(dateRaw.ToLocalTime());
        dateSerialized.Should().Be(dateRawAsLocal);
    }

    [TestMethod]
    public void NEW_Should_deserialize_unspecified_datestring_to_unspecified_date() 
    {
        string dateString = "\"2014-06-02T21:00:00.0000000\""; // unspecified, does not have the 'Z'
        DateTime dateRaw = new DateTime(2014, 6, 2, 21, 0, 0, 0, DateTimeKind.Unspecified);

        JsonSerializerSettings settings = new JsonSerializerSettings();
        settings.DateTimeZoneHandling = DateTimeZoneHandling.Unspecified;
        settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
        DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, settings);                

        Console.WriteLine("date string: " + dateString);
        Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));
        dateSerialized.Kind.Should().Be(DateTimeKind.Unspecified); 
        dateSerialized.Should().Be(dateRaw);
    }

我不是百分百肯定你在這里尋找什么,但我認為假設JSON.Net在沒有一點幫助的情況下滿足你的所有需求是不安全的。 正如牛頓先生所說

JSON中的日期很難。

首先要確定是否要支持接受未指定的日期,或者是否要假設所有傳入的日期都是通用的,即使它們缺少尾隨的Z.

如果您假設所有傳入日期都是通用的,您可以看看它們是否有尾隨Z,如果沒有,則添加它(不完全是生產代碼,但您明白了):

if (!dateString.EndsWith("Z\"", StringComparison.InvariantCultureIgnoreCase))
{
    dateString = dateString.Substring(0, dateString.LastIndexOf("\"", StringComparison.InvariantCultureIgnoreCase)) + "Z\"";
}

假設的這種變化確實要求將您測試的日期修改為Utc。

如果您不想假定傳入日期是通用的,而是將它們視為未指定,則需要通過替換來更改轉換傳入JSON的方式:

JsonSerializerSettings settings = new JsonSerializerSettings();
settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, settings);                

有:

var oConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter();
DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, oConverter);

這將導致一個未指定的日期與dateString完全匹配。 這是你的助手發揮作用的地方:

if (dateSerialized.Kind == DateTimeKind.Unspecified)
{
    dateSerialized = dateSerialized.ToUniversalTime();
}

這意味着完整的,修訂的第一個測試將如下所示,它將通過:

    string dateString = "\"2014-06-02T21:00:00.0000000\"";
    DateTime dateRaw = new DateTime(2014, 6, 2, 21, 0, 0, 0, DateTimeKind.Unspecified);
    DateTime dateRawAsUtc = new DateTime(2014, 6, 3, 4, 0, 0, 0, DateTimeKind.Utc);
    dateRawAsUtc.Should().Be(dateRaw.ToUniversalTime());

    var oConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter();
    DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, oConverter);
    if (dateSerialized.Kind == DateTimeKind.Unspecified)
    {
        dateSerialized = dateSerialized.ToUniversalTime();
    }

    Console.WriteLine("date string: " + dateString);
    Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));

    dateSerialized.Kind.Should().Be(DateTimeKind.Utc); 
    dateSerialized.Should().Be(dateRaw.ToUniversalTime());
    dateSerialized.Should().Be(dateRawAsUtc);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM