Javascript 即使未指定,您能否告诉 JSON.Net 将 DateTime 序列化为 Utc?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10302902/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can you tell JSON.Net to serialize DateTime as Utc even if unspecified?
提问by C.J.
Dates in my database are stored as Utc. But when I retreieve them w/ the entity framework they come out as type unspecified.
我的数据库中的日期存储为 Utc。但是当我使用实体框架检索它们时,它们会以未指定的类型出现。
When JSON.Net serializes them they are not in Utc format. Is there a way to tell JSON.Net to serialize DateTimes as Utc even if their type is not specified as Utc?
当 JSON.Net 序列化它们时,它们不是 Utc 格式。有没有办法告诉 JSON.Net 将 DateTimes 序列化为 Utc,即使它们的类型没有指定为 Utc?
回答by James Newton-King
Set DateTimeZoneHandling
on JsonSerializerSettings
to Utc
. That will convert all dates to UTC before serializing them.
设置DateTimeZoneHandling
上JsonSerializerSettings
要Utc
。这将在序列化之前将所有日期转换为 UTC。
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
回答by JustMaier
The response above totally works, and so I used that to create an attribute to convert an API response from PST to UTC.
上面的响应完全有效,所以我用它来创建一个属性,将 API 响应从 PST 转换为 UTC。
First I needed to create a JsonConverter
首先我需要创建一个 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;}
}
回答by Ekus
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:
正如@dez 在评论中提到的,您可以在从 DB 加载它们并在序列化它们之前直接在 .net 代码中将 DateTime 对象“标记”为 UTC:
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
回答by Ilkka
To me, it was simpler to create the UTC converter for DateTime properties (based on the implementation of the Newtonsoft.Json.Converters.IsoDateTimeConverter).
对我来说,为 DateTime 属性创建 UTC 转换器更简单(基于 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; }
}
回答by Iain
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;
});