Ray*_*ond 7 c# timezone serialization datetime json.net
在常规.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);
}
Run Code Online (Sandbox Code Playgroud)
我不能 100% 确定您在这里寻找什么,但我认为假设 JSON.Net 无需一点帮助就能满足您的所有需求是不安全的。正如牛顿先生所说:
JSON 中的日期很难。
第一件事是确定是否要支持接受未指定的日期,或者是否要假设所有传入日期都是通用的,即使它们缺少尾随的 Z。
如果您假设所有传入日期都是通用的,您只需查看它们是否有尾随 Z,如果没有,则添加它(不完全是生产代码,但您明白了):
if (!dateString.EndsWith("Z\"", StringComparison.InvariantCultureIgnoreCase))
{
dateString = dateString.Substring(0, dateString.LastIndexOf("\"", StringComparison.InvariantCultureIgnoreCase)) + "Z\"";
}
Run Code Online (Sandbox Code Playgroud)
这种假设的变化确实需要将您测试的日期修改为 Utc。
如果您不想假设传入日期是通用的,而是将它们视为未指定的,则需要通过替换以下内容来更改转换传入 JSON 的方式:
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
settings.DateFormatHandling = DateFormatHandling.IsoDateFormat;
DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, settings);
Run Code Online (Sandbox Code Playgroud)
和:
var oConverter = new Newtonsoft.Json.Converters.IsoDateTimeConverter();
DateTime dateSerialized = JsonConvert.DeserializeObject<DateTime>(dateString, oConverter);
Run Code Online (Sandbox Code Playgroud)
这将导致与 dateString 完全匹配的未指定日期。这是您的帮助之手发挥作用的地方:
if (dateSerialized.Kind == DateTimeKind.Unspecified)
{
dateSerialized = dateSerialized.ToUniversalTime();
}
Run Code Online (Sandbox Code Playgroud)
这意味着完整的、修订后的第一个测试将如下所示,它将通过:
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);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
6601 次 |
| 最近记录: |