【问题标题】:DataContractJsonSerializer DateTime implicit timezone conversionDataContractJsonSerializer DateTime 隐式时区转换
【发布时间】:2011-08-06 06:07:45
【问题描述】:

我在数据库中有一个日期时间,我使用实体框架从数据库中检索它,然后通过 JSON API 通过 DataContractJsonSerializer 传递数据。

日期时间字段中的时间似乎已根据服务器的本地时区进行了调整,同时在 DataContractJsonSerializer 中进行处理。纪元表示的时间比预期时间提前 1 小时。 DateTime 类型是 UTC,但以前它是未指定的,我遇到了同样的问题。

在我的应用程序中,我希望在客户端而不是服务器上显式地在时区之间进行转换,因为这样更有意义。我对这种隐式功能感到惊讶,因为我的日期时间值应该是简单的值,就像整数一样。

谢谢

【问题讨论】:

    标签: c# .net json wcf-rest datacontractjsonserializer


    【解决方案1】:

    如果您的 DateTime.Kind 等于 Local OR Unspecified,DataContractJsonSerializer 将输出时区部分 (+zzzz)。此行为与 XmlSerializer 不同,后者仅在 Kind 等于 Unspecified 时输出时区部分。

    如果好奇,请查看JsonWriterDelegator 的源代码,其中包含以下方法:

     internal override void WriteDateTime(DateTime value) 
        {
            // ToUniversalTime() truncates dates to DateTime.MaxValue or DateTime.MinValue instead of throwing 
            // This will break round-tripping of these dates (see bug 9690 in CSD Developer Framework)
            if (value.Kind != DateTimeKind.Utc)
            {
                long tickCount = value.Ticks - TimeZone.CurrentTimeZone.GetUtcOffset(value).Ticks; 
                if ((tickCount > DateTime.MaxValue.Ticks) || (tickCount < DateTime.MinValue.Ticks))
                { 
                    throw DiagnosticUtility.ExceptionUtility.ThrowHelperError( 
                        XmlObjectSerializer.CreateSerializationException(SR.GetString(SR.JsonDateTimeOutOfRange), new ArgumentOutOfRangeException("value")));
                } 
            }
    
            writer.WriteString(JsonGlobals.DateTimeStartGuardReader);
            writer.WriteValue((value.ToUniversalTime().Ticks - JsonGlobals.unixEpochTicks) / 10000); 
    
            switch (value.Kind) 
            { 
                case DateTimeKind.Unspecified:
                case DateTimeKind.Local: 
                    // +"zzzz";
                    TimeSpan ts = TimeZone.CurrentTimeZone.GetUtcOffset(value.ToLocalTime());
                    if (ts.Ticks < 0)
                    { 
                        writer.WriteString("-");
                    } 
                    else 
                    {
                        writer.WriteString("+"); 
                    }
                    int hours = Math.Abs(ts.Hours);
                    writer.WriteString((hours < 10) ? "0" + hours : hours.ToString(CultureInfo.InvariantCulture));
                    int minutes = Math.Abs(ts.Minutes); 
                    writer.WriteString((minutes < 10) ? "0" + minutes : minutes.ToString(CultureInfo.InvariantCulture));
                    break; 
                case DateTimeKind.Utc: 
                    break;
            } 
            writer.WriteString(JsonGlobals.DateTimeEndGuardReader);
        }
    

    我已经在我的机器上运行了以下测试

    var jsonSerializer = new DataContractJsonSerializer(typeof(DateTime));
    var date = DateTime.UtcNow;
            Console.WriteLine("original date = " + date.ToString("s"));
            using (var stream = new MemoryStream())
            {
                jsonSerializer.WriteObject(stream, date);
    
                stream.Position = 0;
                var deserializedDate = (DateTime)jsonSerializer.ReadObject(stream);
                Console.WriteLine("deserialized date = " + deserializedDate.ToString("s"));
    
            }
    

    产生预期的输出:

    original date = 2011-04-19T10:24:39
    deserialized date = 2011-04-19T10:24:39
    

    因此在某些时候您的日期必须是未指定的或本地的。

    从数据库中取出后,通过调用将类型从 Unspecified 转换为 Utc

     entity.Date = DateTime.SpecifyKind(entity.Date, DateTimeKind.Utc);
    

    并且不要忘记像我一样将SpecifyKind 的返回值分配回您的对象

    【讨论】:

    • 我的datetime序列化为1303500600000+0000
    • 您的样本序列化为“\/Date(1303220156217)\/”,而我的样本序列化为“\/Date(1303500600000+0000)\/”。我不知道为什么它包括 +0000
    • 您确定 DateTimeKind=UTC 吗?我刚刚在我的机器上再次尝试,当 DateTimeKind 不等于 UTC(本地或未指定)时,输出时区。我也刚刚查看了源代码,如果 DateTimeKind==UTC 将不会输出时区
    • 你能在你身边运行我的样本来检查你没有得到 +zzzzz 输出吗?
    • 哦,是的,对不起,我以为它是自动完成的。都是因为我的 DateTime 上的 Kind 没有指定,所以序列化器决定加上一个时区说明符,这使得后续反序列化的 DataContractJsonSerializer 认为需要将时间值调整为本地时间。实际上,我希望我的日期时间值与时区无关。我不知道为什么 MS 搞得这么复杂。如果 MS 忽略了这种隐含的行为,那就很简单了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-08-06
    • 2015-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-12
    • 1970-01-01
    相关资源
    最近更新 更多