DataContractJsonSerializer错误地序列化DateTime对象,纪元秒是正确的但时区偏移是不正确的 [英] DataContractJsonSerializer serializes DateTime objects incorrectly, the epoch seconds are correct but the timezone offset is incorrect

查看:85
本文介绍了DataContractJsonSerializer错误地序列化DateTime对象,纪元秒是正确的但时区偏移是不正确的的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们有一个WCF应用程序,它有一些服务以json格式返回DateTime对象(正在使用webHttpBinding)。问题是 - 当服务器位于新西兰时区时,某些日期,序列化日期中的时区偏移量显示
错误。这给我们带来了一些问题。

We have a WCF application which have a few services that return DateTime objects in json format(webHttpBinding is being used). The problem is - when the server is in New Zealand timezone, with certain dates, the timezone offset in the serialized dates shows up incorrectly. This is creating few problems for us.

实际问题是使用默认的json序列化程序 - DataContractJsonSerializer,下面的代码演示了这一点。基本上,如果日期与DST的开始/结束日期相同,则时序偏移量在序列化日期中显示不正确。下面的代码使用
一个类似的日期 - 2002-03-17(DST在第3个周日凌晨3:00结束),正确的时区偏移是UTC + 13,但序列化日期显示UTC + 12。实际问题似乎是在未指定类型的日期上调用ToLocalTime()。
另外,请注意问题在于DST结束日期和开始日期,其余日期偏移显示正常。

The actual problem is with the default json serializer - DataContractJsonSerializer, below code demonstrates this. Basically, if the date is same as the start/end date of DST, the timezone offset shows up incorrect in the serialized date. Below code uses a similar date - 2002-03-17(DST ends at 3rd sunday 3:00 am) for which the correct timezone offset is UTC+13, but instead the serialized date shows UTC+12. The actual problem appears to be with calling ToLocalTime() over a date with unspecified kind. Also, note that the problem is with DST end and start dates, for the rest of dates the offset shows up fine.

将机器的时区更改为  UTC + 12奥克兰,惠灵顿,然后编译并运行下面的代码。  

Change your machine's timezone to UTC+12 Auckland, Wellington before you compile and run below code. 

using System;
using System.Linq;
using System.Globalization;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;
using System.Text;
using System.IO;
[DataContract]
public class DateTimeTest
{
  public DateTimeTest()
  {
    this.UnspecifiedDate = new DateTime(2002, 03, 17, 0, 0, 0); 
    this.LocalDate = new DateTime(2002, 03, 17, 0, 0, 0, DateTimeKind.Local);
  }  
  [DataMember]
  public DateTime UnspecifiedDate { get; set; }  
  [DataMember]
  public DateTime LocalDate { get; set; }  
  
  public static void Main(string[] a)
  {
    // below makes the DataContractJsonSerializer use TimeZoneInfo instead of TimeZone, 
    // TimeZone appears to be even more buggy for historical dates
    // with TimeZoneInfo the only faulty dates are 2 per year, 
    // which mark the DST (i.e a day in April/March and day in October/September)
    AppContext.SetSwitch("Switch.System.Runtime.Serialization.DoNotUseTimeZoneInfo", false);

    var obj = new DateTimeTest();          
    Console.Write("Serialized Dates, the epoch seconds are same & correct for both local and unspecified dates ");
    Console.WriteLine("but the timezone offset is incorrect for unspecified date");
    
    // outputs {"LocalDate":"\/Date(1016276400000+1300)\/","UnspecifiedDate":"\/Date(1016276400000+1200)\/"}
    Console.WriteLine(Serialize(obj));

    // this is what serializer uses internally to get the offset, 
    // the problem only happens when you input an unspecifiedDate and convert it to localtime
    Console.WriteLine("\r\nGetUtcOffset(unspecifiedDate.ToLocalTime())");
    Console.WriteLine(TimeZoneInfo.Local.GetUtcOffset(obj.UnspecifiedDate.ToLocalTime()));// outputs 12:00:00  
    
    Console.WriteLine("\r\nGetUtcOffset(unspecifiedDate)");
    Console.WriteLine(TimeZoneInfo.Local.GetUtcOffset(obj.UnspecifiedDate));// outputs 13:00:00  

    Console.WriteLine("\r\nGetUtcOffset(localDate)");
    Console.WriteLine(TimeZoneInfo.Local.GetUtcOffset(obj.LocalDate));// outputs 13:00:00    
  }  
  private static string Serialize(DateTimeTest obj)
  {      
    using (MemoryStream stream = new MemoryStream())
    {
      new DataContractJsonSerializer(typeof(DateTimeTest)).WriteObject(stream, obj);
      return Encoding.Default.GetString(stream.ToArray());
    }  
  }  
}

所以,有人可以帮助我以最好的方式解决这个问题影响最小?

So, could someone help me with solving this in best manner with least impacts?

注意:一些可能的解决方案是 -  

Note: Some possible solutions are - 

a。为您在应用程序中使用的所有日期指定日期时间类型为Local,但这听起来不太可行,也不确定影响是否为b
b。将DataContractJsonSerializer替换为其他一些序列化程序(JSON.net似乎没有遇到这个问题,它似乎没有在未指定的日期调用ToLocalTime)或者,你可以保留DataContractJsonSerializer,但你可以将
更改为本地类型对于所有DateTime对象在序列化之前。两者都需要滚动你自己的自定义消息格式化程序,这看起来并不简单,看起来很有影响力(即使有这个非常好的帖子 -   https://blogs.msdn.microsoft.com/carlosfigueira/2011/05/02/wcf-extensibility- message-formatters /),
尝试向管道添加自定义消息格式化程序并保持序列化过程与以前完全相同对我来说非常棘手。

a. Specify the date time kind as Local for all the dates you use in your application, but this does not sound feasible, not sure about the impacts too
b. Replace the DataContractJsonSerializer with some other serializer(JSON.net does not appear to suffer this problem, it does not appear to call ToLocalTime over unspecified dates) alternatively, you can keep DataContractJsonSerializer, but instead you can change the kind to local for all DateTime objects before they get serialized. Both require rolling your own custom message formatter which does not look straightforward and looks impactful (even with this very good post - https://blogs.msdn.microsoft.com/carlosfigueira/2011/05/02/wcf-extensibility-message-formatters/), trying to add a custom message formatter to the pipeline and keeping the serialization process exactly the same as before appears very tricky to me.

谢谢。

推荐答案

嗨Nagarjuna.B,

Hi Nagarjuna.B,

从我的机器上,我找不到一个名为新西兰的时区,我无法在我身边重现你的问题。请指导我如何设置时区到新西兰。

From my machine, I could not find a time zone that named New Zealand, and I could not reproduce your issue on my side. please guide me how to set time zone to New Zealand.

祝你好运,

张龙


这篇关于DataContractJsonSerializer错误地序列化DateTime对象,纪元秒是正确的但时区偏移是不正确的的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆