c# – json.net datetime的序列化/反序列化’未指定’

前端之家收集整理的这篇文章主要介绍了c# – json.net datetime的序列化/反序列化’未指定’前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
在常规的.net中,
如果我们有一个DateTimeKind.Unspecified的时间
如果我们转换ToLocal – 它假定转换时输入日期是UTC.
如果我们转换为ToUniversal – 它假定转换时输入日期是本地的

但是,在JSON.Net中,如果我们在JSON.Net中的字符串日期未指定,它似乎没有这个逻辑?看看我下面的测试用例 – 我做错了吗?或者这是设计?或JSON.Net中的错误
谢谢!

  1. // TODO: This Fails with output
  2. // date string: "2014-06-02T21:00:00.0000000"
  3. // date serialized: 2014-06-02T21:00:00.0000000Z
  4. // Expected date and time to be <2014-06-03 04:00:00>,but found <2014-06-02 21:00:00>.
  5. [TestMethod]
  6. public void NEW_Should_deserialize_unspecified_datestring_to_utc_date()
  7. {
  8. string dateString = "\"2014-06-02T21:00:00.0000000\"";
  9. DateTime dateRaw = new DateTime(2014,6,2,21,DateTimeKind.Unspecified);
  10. DateTime dateRawAsUtc = new DateTime(2014,3,4,DateTimeKind.Utc);
  11. dateRawAsUtc.Should().Be(dateRaw.ToUniversalTime());
  12.  
  13. JsonSerializerSettings settings = new JsonSerializerSettings();
  14. settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
  15. settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
  16. DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString,settings);
  17.  
  18. Console.WriteLine("date string: " + dateString);
  19. Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));
  20.  
  21. dateSerialized.Kind.Should().Be(DateTimeKind.Utc);
  22. dateSerialized.Should().Be(dateRaw.ToUniversalTime());
  23. dateSerialized.Should().Be(dateRawAsUtc);
  24. }
  25.  
  26. // TODO: This Fails with output
  27. // date string: "2014-06-02T21:00:00.0000000"
  28. // date serialized: 2014-06-02T21:00:00.0000000-07:00
  29. // Expected date and time to be <2014-06-02 14:00:00>,but found <2014-06-02 21:00:00>.
  30. [TestMethod]
  31. public void NEW_Should_deserialize_unspecified_datestring_to_local_date()
  32. {
  33. string dateString = "\"2014-06-02T21:00:00.0000000\"";
  34. DateTime dateRaw = new DateTime(2014,DateTimeKind.Unspecified);
  35. DateTime dateRawAsLocal = new DateTime(2014,14,DateTimeKind.Local);
  36. dateRawAsLocal.Should().Be(dateRaw.ToLocalTime());
  37.  
  38. JsonSerializerSettings settings = new JsonSerializerSettings();
  39. settings.DateTimeZoneHandling = DateTimeZoneHandling.Local;
  40. settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
  41. DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString,settings);
  42.  
  43. Console.WriteLine("date string: " + dateString);
  44. Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));
  45.  
  46. dateSerialized.Kind.Should().Be(DateTimeKind.Local);
  47. dateSerialized.Should().Be(dateRaw.ToLocalTime());
  48. dateSerialized.Should().Be(dateRawAsLocal);
  49. }
  50.  
  51. [TestMethod]
  52. public void NEW_Should_deserialize_unspecified_datestring_to_unspecified_date()
  53. {
  54. string dateString = "\"2014-06-02T21:00:00.0000000\""; // unspecified,does not have the 'Z'
  55. DateTime dateRaw = new DateTime(2014,DateTimeKind.Unspecified);
  56.  
  57. JsonSerializerSettings settings = new JsonSerializerSettings();
  58. settings.DateTimeZoneHandling = DateTimeZoneHandling.Unspecified;
  59. settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
  60. DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString,settings);
  61.  
  62. Console.WriteLine("date string: " + dateString);
  63. Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));
  64. dateSerialized.Kind.Should().Be(DateTimeKind.Unspecified);
  65. dateSerialized.Should().Be(dateRaw);
  66. }

解决方法

我不是百分百肯定你在这里寻找什么,但我认为假设JSON.Net在没有一点帮助的情况下满足你的所有需求是不安全的.如 Mr. Newton says

Dates in JSON are hard.

首先要确定是否要支持接受未指定的日期,或者是否要假设所有传入的日期都是通用的,即使它们缺少尾随的Z.

如果您假设所有传入日期都是通用的,您可以看看它们是否有尾随Z,如果没有,则添加它(不完全是生产代码,但您明白了):

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

假设的这种变化确实要求将您测试的日期修改为Utc.

如果您不想假定传入日期是通用的,而是将它们视为未指定,则需要通过替换来更改转换传入JSON的方式:

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

有:

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

这将导致一个未指定的日期与dateString完全匹配.这是你的助手发挥作用的地方:

  1. if (dateSerialized.Kind == DateTimeKind.Unspecified)
  2. {
  3. dateSerialized = dateSerialized.ToUniversalTime();
  4. }

这意味着完整的,修订的第一个测试将如下所示,它将通过:

  1. string dateString = "\"2014-06-02T21:00:00.0000000\"";
  2. DateTime dateRaw = new DateTime(2014,DateTimeKind.Unspecified);
  3. DateTime dateRawAsUtc = new DateTime(2014,DateTimeKind.Utc);
  4. dateRawAsUtc.Should().Be(dateRaw.ToUniversalTime());
  5.  
  6. var oConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter();
  7. DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString,oConverter);
  8. if (dateSerialized.Kind == DateTimeKind.Unspecified)
  9. {
  10. dateSerialized = dateSerialized.ToUniversalTime();
  11. }
  12.  
  13. Console.WriteLine("date string: " + dateString);
  14. Console.WriteLine("date serialized: " + dateSerialized.ToString("o"));
  15.  
  16. dateSerialized.Kind.Should().Be(DateTimeKind.Utc);
  17. dateSerialized.Should().Be(dateRaw.ToUniversalTime());
  18. dateSerialized.Should().Be(dateRawAsUtc);

猜你在找的C#相关文章