我有一个动态对象,其中包含日期(以及其他数据)。
其中一些日期具有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
}
这意味着我只想在DateTime的类型为Utc时添加一个“ Z” 。
使用IsoDateTimeConverter
和/或JsonSerializerSettings
可能吗?
答案 0 :(得分:2)
我将使用IsoDateTimeConverter
而不设置DateTimeFormat
,它会输出完整的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:
小数部分的小数位数没有限制。但是,小数位数需要经过通信各方的同意。
答案 1 :(得分:1)
几件事:
您不应该将DateTime
的值与DateTimeKind.Local
的值进行序列化,不要偏移。由于是当地时间,因此应提供当地时间。否则,接收方可能会在本地时间 中解释该值-可能与发送方的本地时间不同。
The K
specifier与DateTimeStyles.RoundTripKind
配对时,可以正确地序列化所有受支持的ISO 8601格式:
DateTimeKind.Utc
被序列化并附加了Z
DateTimeKind.Local
被序列化并附加了本地偏移量,例如-07:00
DateTimeKind.Unspecified
被序列化而未附加任何内容这些是IsoDateTimeConverter
已经给出的默认值,DateTime
是RoundTripKind
值的默认转换器。因此,在大多数情况下,您根本不需要指定任何转换器。
ISO 8601允许任意长度的分数秒。DateTime
样式给出7个小数,因为这是isoDateTimeConverter.DateTimeFormat = "yyyy-MM-dd'T'HH:mm:ssK";
支持的精度。 JavaScript中的客户端代码通常仅支持毫秒,因此在客户端上解析时多余的小数将被截断。
如果必须截断小数,则:
DateTimeKind.Unspecified
如果您觉得必须截断本地时间的偏移量,更好的方法是在序列化之前使用DateTime.SpecifyKind
设置JsonConverter
。
如果您想全局更改此 ,则可以创建自己的IsoDateTimeConverter
。您可以继承ReadJson
并覆盖WriteJson
和JsonConverter
方法,也可以直接从var now = DateTime.Now;
var nums = new List<Num>
{
new Num { Min = now, Max = now.AddDays(1) },
new Num { Min = now.AddDays(10), Max = now.AddDays(50) },
new Num { Min = now.AddDays(51), Max = now.AddDays(100) },
};
var minMaxNum = nums.Select(num => new Num
{
Min = nums.Min(_ => _.Min),
Max = nums.Max(_ => _.Max),
}).First();
开始。由于我不推荐这种方法,因此我不会在此处添加一个。