C# DataContractJsonSerializer日期时间隐式时区转换

C# DataContractJsonSerializer日期时间隐式时区转换,c#,.net,json,wcf-rest,datacontractjsonserializer,C#,.net,Json,Wcf Rest,Datacontractjsonserializer,我在数据库中有一个日期时间,我使用实体框架从数据库中检索它,然后通过DataContractJsonSerializer通过JSONAPI传递数据 在DataContractJsonSerializer中处理时,日期时间字段中的时间似乎已根据服务器的本地时区进行了调整。表示时间的历元比预期时间提前1小时。DateTime类型是UTC,但之前没有指定,我也遇到了同样的问题 在我的应用程序中,我希望在客户端而不是服务器端显式地在时区之间转换,因为这更有意义。我对这种隐式功能感到惊讶,因为我的date

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

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

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


谢谢

如果您的DateTime.Kind等于本地或未指定,则DataContractJsonSerializer
将输出时区部分(+zzzzzz)。这种行为不同于XmlSerializer,XmlSerializer只在种类等于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);
    }
产生预期输出的:

original date = 2011-04-19T10:24:39
deserialized date = 2011-04-19T10:24:39
因此,在某些情况下,您的日期必须是未指定的或本地的

将其从数据库中拉出后,通过调用

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

别忘了像我一样将
SpecifyKind
的返回值赋回到对象中

我的datetime序列化为130350600000+00000您的示例序列化为“\/Date(1303220156217)\/”,而我的序列化为“\/Date(130350600000+0000)\/”。我不知道为什么它包含+00000您确定DateTimeKind=UTC吗?我只是在我的机器上再次尝试,当DateTimeKind不等于UTC(本地或未指定)时,将输出时区。我刚才也看过源代码,如果DateTimeKind==UTC,时区将不会输出。您可以运行我的示例检查您是否没有得到+zzzzz输出吗?哦,是的,对不起,我以为它是自动完成的。这都是因为DateTime上的类型未指定,所以序列化程序决定添加一个时区说明符,这使得随后的反序列化DataContractJsonSerializer认为需要将时间值调整为本地时间。实际上,我希望我的日期时间值是时区不可知的。我不知道为什么微软让它如此复杂;如果MS忽略了这种含蓄的行为,那就简单了。
 entity.Date = DateTime.SpecifyKind(entity.Date, DateTimeKind.Utc);