Can you tell JSON.Net to serialize DateTime as Utc even if unspecified?

前端 未结 5 946
遇见更好的自我
遇见更好的自我 2020-11-29 03:45

Dates in my database are stored as Utc. But when I retreieve them w/ the entity framework they come out as type unspecified.

When JSON.Net serializes them they are n

相关标签:
5条回答
  • 2020-11-29 04:12

    The response above totally works, and so I used that to create an attribute to convert an API response from PST to UTC.

    First I needed to create a JsonConverter

    public class UTCDateTimeConverter : Newtonsoft.Json.JsonConverter {
        private TimeZoneInfo pacificZone = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
        public override bool CanConvert(Type objectType) {
            return objectType == typeof(DateTime);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) {
            if (reader.Value == null) return null;
            var pacificTime = DateTime.Parse(reader.Value.ToString());
            return TimeZoneInfo.ConvertTimeToUtc(pacificTime, pacificZone);
        }
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) {
            writer.WriteValue(TimeZoneInfo.ConvertTimeFromUtc((DateTime) value, pacificZone));
        }
    }
    

    Then I had to apply that to the properties that needed to be converted

    public class Order{
        [JsonConverter(typeof(UTCDateTimeConverter))]
        public DateTime OrderDate {get;set;}
    }
    
    0 讨论(0)
  • 2020-11-29 04:18

    I used the accepted answer however applied to the default settings:

            JsonConvert.DefaultSettings = (() =>
            {
                var settings = new JsonSerializerSettings();
                settings.Converters.Add(new StringEnumConverter());
                settings.Formatting = Formatting.Indented;
                settings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
                return settings;
            });
    
    0 讨论(0)
  • 2020-11-29 04:32

    To me, it was simpler to create the UTC converter for DateTime properties (based on the implementation of the Newtonsoft.Json.Converters.IsoDateTimeConverter).

    public class UtcJsonDateTimeConverter : DateTimeConverterBase
    {
        private const string DefaultDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFZ";
    
        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            string text;
    
            if (value is DateTime dateTime)
            {
                text = dateTime.ToString(DefaultDateTimeFormat, CultureInfo.InvariantCulture);
            }
            else
            {
                throw new JsonSerializationException(
                    $"Unexpected value when converting date. Expected DateTime or DateTimeOffset, got {value.GetType()}.");
            }
    
            writer.WriteValue(text);
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            bool nullable = objectType == typeof(DateTime?);
            if (reader.TokenType == JsonToken.Null)
            {
                if (!nullable)
                {
                    throw new JsonSerializationException($"Cannot convert null value to {objectType}.");
                }
    
                return null;
            }
    
            if (reader.TokenType == JsonToken.Date)
            {
                return reader.Value;
            }
            else if (reader.TokenType != JsonToken.String)
            {
                throw new JsonSerializationException($"Unexpected token parsing date. Expected String, got {reader.TokenType}.");
            }
    
            string date_text = reader.Value.ToString();
    
            if (string.IsNullOrEmpty(date_text) && nullable)
            {
                return null;
            }
    
            return DateTime.Parse(date_text, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal);
        }
    }
    
    public class SomeEntity
    {
    
       [JsonProperty(PropertyName = "id", Order = 1)]
       public int ID { get; set; }
    
       [JsonProperty(PropertyName = "created", Order = 2)]
       [JsonConverter(typeof(UtcJsonDateTimeConverter))]
       public DateTime Created { get; set; }
    }
    
    0 讨论(0)
  • As @dez mentioned in a comment, you can "mark" the DateTime objects as UTC directly in .net code right after LOADING them from DB and BEFORE serializing them:

    var item = GetItemFromDb(...);
    
    // mark appropriate DateTime fields manually as needed
    item.OrderDate = DateTime.SpecifyKind(item.OrderDate, DateTimeKind.Utc);
    
    // now it will be serialized to "2018-10-17T16:21:23.507Z" with the Z at the end
    // and javascript will parse it properly and convert to local timezone as needed
    
    0 讨论(0)
  • 2020-11-29 04:34

    Set DateTimeZoneHandling on JsonSerializerSettings to Utc. That will convert all dates to UTC before serializing them.

    public void SerializeObjectDateTimeZoneHandling()
    {
      string json = JsonConvert.SerializeObject(
        new DateTime(2000, 1, 1, 1, 1, 1, DateTimeKind.Unspecified),
        new JsonSerializerSettings
        {
          DateTimeZoneHandling = DateTimeZoneHandling.Utc
        });
    
      Assert.AreEqual(@"""2000-01-01T01:01:01Z""", json);
    }
    

    Documentation: DateTimeZoneHandling setting

    0 讨论(0)
提交回复
热议问题