使用 System.Text.Json 反序列化 Json 时间戳
Deserialise Json Timestamp with System.Text.Json
我正在尝试反序列化以下 JSON
{"serverTime":1613967667240}
变成下面的一个对象class
public class ApiServerTime
{
[JsonPropertyName("serverTime")]
public DateTime ServerTime
{
get;
private set;
}
}
使用以下命令:
JsonSerializer.Deserialize<ApiServerTime>(jsonString);
但生成的对象包含 ServerTime == DateTime.MinValue
。我做错了什么?
- 根据 What is the “right” JSON date format? 你最好使用 ISO 8601
"\"\/Date(1335205592410)\/\"" .NET JavaScriptSerializer
"\"\/Date(1335205592410-0500)\/\"" .NET DataContractJsonSerializer
"2012-04-23T18:25:43.511Z" JavaScript built-in JSON object
"2012-04-21T18:25:43-05:00" ISO 8601
- 你也可以使用 JsonMicrosoftDateTimeConverter 来反序列化它。但它需要更改 json 演示文稿。你可以参考 link System.Text.Json DateTime & DateTimeOffset “/Date()/” serialization
{
"Date": "\/Date(1580803200000-0800)\/"
}
- 最后,你可以使用临时模型保存当前时间戳,然后转换它。
public class ApiServerTime{
public long ServerTime{get;set;}
public static DateTime UnixTimeStampToDateTime( double unixTimeStamp )
{
// Unix timestamp is seconds past epoch
System.DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds( unixTimeStamp ).ToLocalTime();
return dtDateTime;
}
}
您也可以为 System.Text.Json 注册自定义日期格式化程序。
https://docs.microsoft.com/en-us/dotnet/standard/datetime/system-text-json-support
public class DateTimeConverterForCustomStandardFormatR : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.UnixEpoch.AddMilliseconds(reader.GetInt64());
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
// The "R" standard format will always be 29 bytes.
Span<byte> utf8Date = new byte[29];
bool result = Utf8Formatter.TryFormat(value, utf8Date, out _, new StandardFormat('R'));
Debug.Assert(result);
writer.WriteStringValue(utf8Date);
}
}
string js = "{\"ServerTime\":1613967667240}";
JsonSerializerOptions options = new JsonSerializerOptions();
options.Converters.Add(new DateTimeConverterForCustomStandardFormatR());
var value = JsonSerializer.Deserialize<ApiServerTime>(js, options);
本着构建更好的鼠标陷阱的精神,这里有一个实现支持..
- 以秒或毫秒为单位的 Unix 时间。假设:秒 < 9999 年(DateTime 最大值)和毫秒 > 1978.
- 可为空的日期时间
public class UnixToNullableDateTimeConverter : JsonConverter<DateTime?>
{
public override bool HandleNull => true;
public bool? IsFormatInSeconds { get; set; } = null;
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TryGetInt64(out var time))
{
// if 'IsFormatInSeconds' is unspecified, then deduce the correct type based on whether it can be represented in the allowed .net DateTime range
if (IsFormatInSeconds == true || IsFormatInSeconds == null && time > _unixMinSeconds && time < _unixMaxSeconds)
return DateTimeOffset.FromUnixTimeSeconds(time).LocalDateTime;
return DateTimeOffset.FromUnixTimeMilliseconds(time).LocalDateTime;
}
return null;
}
public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) => throw new NotSupportedException();
private static readonly long _unixMinSeconds = DateTimeOffset.MinValue.ToUnixTimeSeconds() - DateTimeOffset.UnixEpoch.ToUnixTimeSeconds(); // -62_135_596_800
private static readonly long _unixMaxSeconds = DateTimeOffset.MaxValue.ToUnixTimeSeconds() - DateTimeOffset.UnixEpoch.ToUnixTimeSeconds(); // 253_402_300_799
}
我正在尝试反序列化以下 JSON
{"serverTime":1613967667240}
变成下面的一个对象class
public class ApiServerTime
{
[JsonPropertyName("serverTime")]
public DateTime ServerTime
{
get;
private set;
}
}
使用以下命令:
JsonSerializer.Deserialize<ApiServerTime>(jsonString);
但生成的对象包含 ServerTime == DateTime.MinValue
。我做错了什么?
- 根据 What is the “right” JSON date format? 你最好使用 ISO 8601
"\"\/Date(1335205592410)\/\"" .NET JavaScriptSerializer
"\"\/Date(1335205592410-0500)\/\"" .NET DataContractJsonSerializer
"2012-04-23T18:25:43.511Z" JavaScript built-in JSON object
"2012-04-21T18:25:43-05:00" ISO 8601
- 你也可以使用 JsonMicrosoftDateTimeConverter 来反序列化它。但它需要更改 json 演示文稿。你可以参考 link System.Text.Json DateTime & DateTimeOffset “/Date()/” serialization
{
"Date": "\/Date(1580803200000-0800)\/"
}
- 最后,你可以使用临时模型保存当前时间戳,然后转换它。
public class ApiServerTime{
public long ServerTime{get;set;}
public static DateTime UnixTimeStampToDateTime( double unixTimeStamp )
{
// Unix timestamp is seconds past epoch
System.DateTime dtDateTime = new DateTime(1970,1,1,0,0,0,0,System.DateTimeKind.Utc);
dtDateTime = dtDateTime.AddSeconds( unixTimeStamp ).ToLocalTime();
return dtDateTime;
}
}
您也可以为 System.Text.Json 注册自定义日期格式化程序。 https://docs.microsoft.com/en-us/dotnet/standard/datetime/system-text-json-support
public class DateTimeConverterForCustomStandardFormatR : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
return DateTime.UnixEpoch.AddMilliseconds(reader.GetInt64());
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
// The "R" standard format will always be 29 bytes.
Span<byte> utf8Date = new byte[29];
bool result = Utf8Formatter.TryFormat(value, utf8Date, out _, new StandardFormat('R'));
Debug.Assert(result);
writer.WriteStringValue(utf8Date);
}
}
string js = "{\"ServerTime\":1613967667240}";
JsonSerializerOptions options = new JsonSerializerOptions();
options.Converters.Add(new DateTimeConverterForCustomStandardFormatR());
var value = JsonSerializer.Deserialize<ApiServerTime>(js, options);
本着构建更好的鼠标陷阱的精神,这里有一个实现支持..
- 以秒或毫秒为单位的 Unix 时间。假设:秒 < 9999 年(DateTime 最大值)和毫秒 > 1978.
- 可为空的日期时间
public class UnixToNullableDateTimeConverter : JsonConverter<DateTime?>
{
public override bool HandleNull => true;
public bool? IsFormatInSeconds { get; set; } = null;
public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TryGetInt64(out var time))
{
// if 'IsFormatInSeconds' is unspecified, then deduce the correct type based on whether it can be represented in the allowed .net DateTime range
if (IsFormatInSeconds == true || IsFormatInSeconds == null && time > _unixMinSeconds && time < _unixMaxSeconds)
return DateTimeOffset.FromUnixTimeSeconds(time).LocalDateTime;
return DateTimeOffset.FromUnixTimeMilliseconds(time).LocalDateTime;
}
return null;
}
public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options) => throw new NotSupportedException();
private static readonly long _unixMinSeconds = DateTimeOffset.MinValue.ToUnixTimeSeconds() - DateTimeOffset.UnixEpoch.ToUnixTimeSeconds(); // -62_135_596_800
private static readonly long _unixMaxSeconds = DateTimeOffset.MaxValue.ToUnixTimeSeconds() - DateTimeOffset.UnixEpoch.ToUnixTimeSeconds(); // 253_402_300_799
}