我正在构建一个 Web API,但在 DateTimes
的 JSON 序列化方面遇到问题。经过一些测试后,我只能得出结论,Newtonsoft.Json.JsonConvert
和/或 Newtonsoft IsoDateTimeConverter
的行为不是我所期望的。
考虑一下:
// Arrange
var noonUtc = new DateTime(2016, 05, 12, 12, 0, 0, DateTimeKind.Utc);
var noon = new DateTime(2016, 05, 12, 12, 0, 0, DateTimeKind.Unspecified);
var settings = new JsonSerializerSettings();
settings.Converters.Add(new IsoDateTimeConverter
{
Culture = CultureInfo.InvariantCulture,
DateTimeStyles = DateTimeStyles.AdjustToUniversal
});
// Act
var utcJson = JsonConvert.SerializeObject(noonUtc, settings); // "\"2016-05-12T12:00:00Z\""
var json = JsonConvert.SerializeObject(noon, settings); // "\"2016-05-12T10:00:00Z\""
... // Assertions
好的,DateTime
与 DateTimeKind.Unspecified
的时间已从 12 点调整为 10 点。我在斯德哥尔摩,目前比 UTC 早两个小时,所以很公平。
但是,让我们更改序列化器设置以使用 DateTimeStyles.AssumeUniversal
,如下所示:
settings.Converters.Add(new IsoDateTimeConverter
{
Culture = CultureInfo.InvariantCulture,
DateTimeStyles = DateTimeStyles.AssumeUniversal
});
这会产生完全相同的字符串,因此也会将 DateTime
与 DateTimeKind.Unspecified
调整两个小时!难道不应该假设日期时间已经是 UTC 时间并保持原样吗?我在这里缺少什么?
最佳答案
我认为你没有遗漏任何东西;这看起来可能是 IsoDateTimeConverter
中的一个错误。这是来自 source 的相关代码:
if ((_dateTimeStyles & DateTimeStyles.AdjustToUniversal) == DateTimeStyles.AdjustToUniversal
|| (_dateTimeStyles & DateTimeStyles.AssumeUniversal) == DateTimeStyles.AssumeUniversal)
{
dateTime = dateTime.ToUniversalTime();
}
如您所见,在调用 ToUniversalTime()< 之前,它仅查看
;它从不检查日期的 _dateTimeStyles
是否设置为 AdjustToUniversal
或 AssumeUniversal
/Kind
属性。
DateTime.ToUniversalTime()
的文档是这样说的:
Starting with the .NET Framework version 2.0, the value returned by the
ToUniversalTime
method is determined by theKind
property of the currentDateTime
object. The following table describes the possible results.Kind | Results ----------- | ---------------------------------------------------------- Utc | No conversion is performed. Local | The current DateTime object is converted to UTC. Unspecified | The current DateTime object is assumed to be a local time, | and the conversion is performed as if Kind were Local.
所以,是的,在这种情况下转换器绝对不应该调用 ToUniversalTime
。您可能想要report an issue .
目前,您可以通过实现具有正确行为的替换转换器(从原始转换器派生)来解决此问题。这可能更接近您想要的:
public class CorrectedIsoDateTimeConverter : IsoDateTimeConverter
{
private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK";
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
if (value is DateTime)
{
DateTime dateTime = (DateTime)value;
if (dateTime.Kind == DateTimeKind.Unspecified)
{
if (DateTimeStyles.HasFlag(DateTimeStyles.AssumeUniversal))
{
dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Utc);
}
else if (DateTimeStyles.HasFlag(DateTimeStyles.AssumeLocal))
{
dateTime = DateTime.SpecifyKind(dateTime, DateTimeKind.Local);
}
}
if (DateTimeStyles.HasFlag(DateTimeStyles.AdjustToUniversal))
{
dateTime = dateTime.ToUniversalTime();
}
string format = string.IsNullOrEmpty(DateTimeFormat) ? DefaultDateTimeFormat : DateTimeFormat;
writer.WriteValue(dateTime.ToString(format, Culture));
}
else
{
base.WriteJson(writer, value, serializer);
}
}
}
关于datetime - 使用 DateTimeStyles.AssumeUniversal 时,为什么 JsonConvert 会使用 DateTimeKind.Unspecified 更改 DateTimes 的时间?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37203207/