JsonSerializer:区分 DateTime 对象的种类
JsonSerializer: discriminate the Kind of DateTime objects
我有一个包含日期(以及其他数据)的动态对象。
其中一些日期具有 UTC 类型,而其他日期具有本地类型,例如:
var dynamicObject = new
{
utcDate = DateTime.UtcNow, //This one has Kind = DateTimeKind.Utc
localDate = DateTime.Now //This one has Kind = DateTimeKind.Local
}
然后我有一个 JsonSerializer,其工作方式如下:
var isoDateTimeConverter = new IsoDateTimeConverter();
isoDateTimeConverter.DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";
// ^
// Notice this
var serializerSettings = new JsonSerializerSettings();
SerializerSettings.Converters.Add(isoDateTimeConverter);
var response = context.HttpContext.Response;
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(serializerSettings);
serializer.Serialize(writer, dynamicObject);
writer.Flush();
这会创建一个 JSON 字符串,如下所示:
{
"utcDate":"2019-05-02T19:52:20Z",
"localDate":"2019-05-02T15:52:20Z"
}
这是预料之中的,因为我的 isoDateTimeConverter
目前是如何定义的。
但我想连载如下:
{
"utcDate":"2019-05-02T19:52:20Z",
"localDate":"2019-05-02T15:52:20" // <--- no Z
}
意味着我想添加一个 'Z' 只有当 DateTime 的种类是 Utc.
IsoDateTimeConverter
and/or JsonSerializerSettings
这可能吗?
我会在不设置 DateTimeFormat
的情况下使用 IsoDateTimeConverter
,它会输出完整的 DateTime
值,带有几分之一秒,如果 DateTimeKind
是 UTC
或如果 Local
则为“+-HH:mm”格式的时区偏移量(如果 None
则为空字符串)。
否则,K
specifier 将根据您的需要设置值的格式,为与 UTC 的偏移附加相同的值。
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public class Program
{
public static void Main(string[] args)
{
var dynamicObject = new
{
utcDate = DateTime.UtcNow, //This one has Kind = DateTimeKind.Utc
localDate = DateTime.Now //This one has Kind = DateTimeKind.Local
}
;
var isoDateTimeConverter = new IsoDateTimeConverter();
isoDateTimeConverter.DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK";
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(isoDateTimeConverter);
var s = new System.Text.StringBuilder();
using (var w = new System.IO.StringWriter(s))
using (var writer = new JsonTextWriter(w)
{Formatting = Formatting.Indented})
{
var serializer = JsonSerializer.Create(serializerSettings);
serializer.Serialize(writer, dynamicObject);
writer.Flush();
}
Console.WriteLine(s.ToString());
}
}
ISO 8601 格式允许日期和时间的多种变化,达到任意精度。来自 Wikipedia's article on ISO 8601:
There is no limit on the number of decimal places for the decimal fraction. However, the number of decimal places needs to be agreed to by the communicating parties.
几件事:
您不应将 DateTime
值与 DateTimeKind.Local
值序列化而没有偏移量。由于是当地时间,因此应提供本地偏移量。否则接收方可能会在他们的本地时间解释该值——这可能与发送方的不同。
The K
specifier,当与 DateTimeStyles.RoundTripKind
配对时,在所有支持的 ISO 8601 格式中正确序列化:
DateTimeKind.Utc
被序列化并附加 Z
DateTimeKind.Local
被序列化并附加了本地偏移量,例如 -07:00
DateTimeKind.Unspecified
被序列化,没有附加任何内容
这些是 IsoDateTimeConverter
已经给出的默认值,它是 DateTime
值的默认转换器。因此,在大多数情况下,您根本不需要指定任何转换器。
ISO 8601 允许任何长度的小数秒。RoundTripKind
样式给出 7 位小数,因为这是 DateTime
支持的精度。 JavaScript 中的客户端代码通常只支持毫秒,因此在客户端解析时会截断多余的小数。
如果您必须截断小数,则:
isoDateTimeConverter.DateTimeFormat = "yyyy-MM-dd'T'HH:mm:ssK";
如果您觉得必须截断本地时间的偏移量,更好的方法是在序列化之前使用 DateTime.SpecifyKind
设置 DateTimeKind.Unspecified
。
如果您觉得应该全局更改此设置,那么您可以创建自己的 JsonConverter
。您可以继承 IsoDateTimeConverter
并覆盖 ReadJson
和 WriteJson
方法,或者您可以直接从 JsonConverter
开始。由于不推荐这种方式,这里就不加了。
我有一个包含日期(以及其他数据)的动态对象。
其中一些日期具有 UTC 类型,而其他日期具有本地类型,例如:
var dynamicObject = new
{
utcDate = DateTime.UtcNow, //This one has Kind = DateTimeKind.Utc
localDate = DateTime.Now //This one has Kind = DateTimeKind.Local
}
然后我有一个 JsonSerializer,其工作方式如下:
var isoDateTimeConverter = new IsoDateTimeConverter();
isoDateTimeConverter.DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'";
// ^
// Notice this
var serializerSettings = new JsonSerializerSettings();
SerializerSettings.Converters.Add(isoDateTimeConverter);
var response = context.HttpContext.Response;
var writer = new JsonTextWriter(response.Output) { Formatting = Formatting };
var serializer = JsonSerializer.Create(serializerSettings);
serializer.Serialize(writer, dynamicObject);
writer.Flush();
这会创建一个 JSON 字符串,如下所示:
{
"utcDate":"2019-05-02T19:52:20Z",
"localDate":"2019-05-02T15:52:20Z"
}
这是预料之中的,因为我的 isoDateTimeConverter
目前是如何定义的。
但我想连载如下:
{
"utcDate":"2019-05-02T19:52:20Z",
"localDate":"2019-05-02T15:52:20" // <--- no Z
}
意味着我想添加一个 'Z' 只有当 DateTime 的种类是 Utc.
IsoDateTimeConverter
and/or JsonSerializerSettings
这可能吗?
我会在不设置 DateTimeFormat
的情况下使用 IsoDateTimeConverter
,它会输出完整的 DateTime
值,带有几分之一秒,如果 DateTimeKind
是 UTC
或如果 Local
则为“+-HH:mm”格式的时区偏移量(如果 None
则为空字符串)。
否则,K
specifier 将根据您的需要设置值的格式,为与 UTC 的偏移附加相同的值。
using System;
using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
public class Program
{
public static void Main(string[] args)
{
var dynamicObject = new
{
utcDate = DateTime.UtcNow, //This one has Kind = DateTimeKind.Utc
localDate = DateTime.Now //This one has Kind = DateTimeKind.Local
}
;
var isoDateTimeConverter = new IsoDateTimeConverter();
isoDateTimeConverter.DateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ssK";
var serializerSettings = new JsonSerializerSettings();
serializerSettings.Converters.Add(isoDateTimeConverter);
var s = new System.Text.StringBuilder();
using (var w = new System.IO.StringWriter(s))
using (var writer = new JsonTextWriter(w)
{Formatting = Formatting.Indented})
{
var serializer = JsonSerializer.Create(serializerSettings);
serializer.Serialize(writer, dynamicObject);
writer.Flush();
}
Console.WriteLine(s.ToString());
}
}
ISO 8601 格式允许日期和时间的多种变化,达到任意精度。来自 Wikipedia's article on ISO 8601:
There is no limit on the number of decimal places for the decimal fraction. However, the number of decimal places needs to be agreed to by the communicating parties.
几件事:
您不应将
DateTime
值与DateTimeKind.Local
值序列化而没有偏移量。由于是当地时间,因此应提供本地偏移量。否则接收方可能会在他们的本地时间解释该值——这可能与发送方的不同。The
K
specifier,当与DateTimeStyles.RoundTripKind
配对时,在所有支持的 ISO 8601 格式中正确序列化:DateTimeKind.Utc
被序列化并附加Z
DateTimeKind.Local
被序列化并附加了本地偏移量,例如-07:00
DateTimeKind.Unspecified
被序列化,没有附加任何内容
这些是
IsoDateTimeConverter
已经给出的默认值,它是DateTime
值的默认转换器。因此,在大多数情况下,您根本不需要指定任何转换器。ISO 8601 允许任何长度的小数秒。
RoundTripKind
样式给出 7 位小数,因为这是DateTime
支持的精度。 JavaScript 中的客户端代码通常只支持毫秒,因此在客户端解析时会截断多余的小数。如果您必须截断小数,则:
isoDateTimeConverter.DateTimeFormat = "yyyy-MM-dd'T'HH:mm:ssK";
如果您觉得必须截断本地时间的偏移量,更好的方法是在序列化之前使用
DateTime.SpecifyKind
设置DateTimeKind.Unspecified
。如果您觉得应该全局更改此设置,那么您可以创建自己的
JsonConverter
。您可以继承IsoDateTimeConverter
并覆盖ReadJson
和WriteJson
方法,或者您可以直接从JsonConverter
开始。由于不推荐这种方式,这里就不加了。