简体   繁体   English

JsonSerializer:区分DateTime对象的种类

[英]JsonSerializer: discriminate the Kind of DateTime objects

I have a dynamic object that contains dates (among other data). 我有一个包含日期(以及其他数据)的动态对象。

Some of these dates have Kind UTC and others have Kind Local, eg: 这些日期中有一些具有同类UTC,而其他日期则具有同类本地,例如:

var dynamicObject = new 
{
     utcDate = DateTime.UtcNow,    //This one has Kind = DateTimeKind.Utc
     localDate = DateTime.Now      //This one has Kind = DateTimeKind.Local
}

And then I have a JsonSerializer that works as follows: 然后,我有一个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();

Which creates a JSON string as this: 这将创建一个JSON字符串,如下所示:

{
     "utcDate":"2019-05-02T19:52:20Z",
     "localDate":"2019-05-02T15:52:20Z"
}

This is expected because of how my isoDateTimeConverter is currently defined. 这是预期的,因为当前如何定义isoDateTimeConverter

But I'd like to serialize as follows: 但我想序列化如下:

{
     "utcDate":"2019-05-02T19:52:20Z",
     "localDate":"2019-05-02T15:52:20"    // <--- no Z
}

Meaning that I'd like to add a 'Z' only when the Kind of the DateTime is Utc . 这意味着我只想在DateTime的Kind为Utc时添加一个“ Z”。

Is this possible with IsoDateTimeConverter and/or JsonSerializerSettings ? IsoDateTimeConverter和/或JsonSerializerSettings是否可能?

I would either use IsoDateTimeConverter without setting the DateTimeFormat , which outputs the full DateTime value, with fractions of seconds, and a "Z" if the DateTimeKind is UTC or a time zone offset in "+-HH:mm" format if Local (and the empty string if None ). 我要么使用IsoDateTimeConverter而不设置DateTimeFormatIsoDateTimeConverter它将输出完整的DateTime值(以秒为单位),如果DateTimeKindUTC ,则使用“ Z”;如果使用Local (和,则使用“ + -HH:mm”格式的时区偏移量)空字符串(如果为None )。

Otherwise, the K specifier will format the value as you desire, appending the same values for the offset from UTC. 否则, K说明符将根据需要格式化该值,并为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());
    }
}

dotnetfiddle . dotnetfiddle

The ISO 8601 format allows for many variations of dates and times, to arbitrary precision. ISO 8601格式允许日期和时间的多种变化,达到任意精度。 From Wikipedia's article on ISO 8601 : 摘自Wikipedia关于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. 但是,小数位数需要经过通信各方的同意。

A few things: 一些东西:

  • You should not serialize DateTime values with DateTimeKind.Local values without an offset. 您不应该使用没有偏移量的DateTimeKind.Local值序列化DateTime值。 Since it's local time, the local offset should be provided. 由于是当地时间,因此应提供当地时间。 Otherwise the receiver may interpret the value in their local time - which may be different than the sender's. 否则,接收方可能会在本地时间解释该值-可能与发送方的时间不同。

  • The K specifier , when paired with DateTimeStyles.RoundTripKind , properly serializes in all supported ISO 8601 formats: K说明符DateTimeStyles.RoundTripKind配对时,可以正确地序列化所有受支持的ISO 8601格式:

    • DateTimeKind.Utc gets serialized with a Z appended DateTimeKind.Utc被序列化并附加Z
    • DateTimeKind.Local gets serialized with the local offset appended, such as -07:00 DateTimeKind.Local被序列化并附加了本地偏移量,例如-07:00
    • DateTimeKind.Unspecified gets serialized without anything appended DateTimeKind.Unspecified获取序列化,不附加任何内容
  • These are the defaults already given by the IsoDateTimeConverter , which is the default converter for DateTime values. 这些是IsoDateTimeConverter已经给出的默认值,它是DateTime值的默认转换器。 Thus, in most cases you don't need to specify any converter at all. 因此,在大多数情况下,您根本不需要指定任何转换器。

  • Fractional seconds to any length are allowed by ISO 8601. The RoundTripKind style gives 7 decimals because that is the precision supported by DateTime . 小数秒任何长度由ISO 8601所允许的RoundTripKind风格,使7位小数,因为这是支持的精度DateTime Client side code in JavaScript generally supports only milliseconds, so extra decimals would be truncated when parsed on the client. JavaScript中的客户端代码通常仅支持毫秒,因此在客户端上解析时多余的小数将被截断。

  • If you must truncate decimals, then: 如果必须截断小数,则:

     isoDateTimeConverter.DateTimeFormat = "yyyy-MM-dd'T'HH:mm:ssK"; 
  • If you feel like you must truncate offsets for local time, the better way would be to set DateTimeKind.Unspecified using DateTime.SpecifyKind before serialization. 如果您觉得必须截断本地时间的偏移量,那么更好的方法是在序列化之前使用DateTime.SpecifyKind设置DateTimeKind.Unspecified

  • If you feel like you should change this globally , then you would create your own JsonConverter . 如果您觉得应该全局更改此设置,则可以创建自己的JsonConverter You could inherit from the IsoDateTimeConverter and override the ReadJson and WriteJson methods, or you could just start directly from JsonConverter . 您可以从IsoDateTimeConverter继承并重写ReadJsonWriteJson方法,也可以直接从JsonConverter开始。 Since I don't recommend this approach, I won't add one here. 由于我不推荐这种方法,因此在此不再赘述。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM