由DataContractJsonSerializer
为DateTimeOffset
和DateTime
生成的JSON已记录。来自Dates/Times and JSON:
DateTimeOffset在JSON中表示为复杂类型:{"DateTime":dateTime,"OffsetMinutes":offsetMinutes}
。 offsetMinutes
成员是与感兴趣事件的位置相关联的格林威治标准时间(GMT)的本地时间偏移,该时间现在也称为协调世界时(UTC)。 dateTime
成员表示感兴趣事件发生时的时间实例(再次,当使用ASP.NET AJAX时,它成为JavaScript中的DateTime;当不使用时,它成为字符串)。序列化时,dateTime成员始终在GMT中序列化。因此,如果描述纽约时间凌晨3:00,则dateTime的时间部分为8:00 AM,offsetMinutes为300(减去GMT的300分钟或5小时)。
注意
DateTime和DateTimeOffset对象,当序列化为JSON时,仅将信息保留为毫秒级。序列化过程中会丢失亚毫秒级的值(微秒/纳秒)。
并且来自DateTime Wire Format:
DateTime值以"/Date(700000+0500)/"
的形式显示为JSON字符串,其中第一个数字(在提供的示例中为700000)是GMT时区中的毫秒数,自此以来的常规(非夏令时)时间1970年1月1日午夜。该数字可能为负值,代表较早的时间。在示例中,由“ +0500”组成的部分是可选的,它指示时间属于本地时间-也就是说,应在反序列化时将其转换为本地时区。如果不存在,则将时间反序列化为Utc。实际数字(在此示例中为“ 0500”)及其符号(+或-)将被忽略。
对于Newtonsoft,请参阅文档页面Serializing Dates in JSON,以了解如何序列化日期和时间。默认情况下,使用ISO 8601格式的字符串,但支持多种格式。
现在,可以通过设置DataContractJsonSerializerSettings.DateTimeFormat
自定义数据协定DateTime
的格式:
var settings = new DataContractJsonSerializerSettings
{
DateTimeFormat = new DateTimeFormat("yyyy-MM-ddTHH\\:mm\\:ss.ffFFFFFzzz",CultureInfo.InvariantCulture)
{
},};
DataContractJsonSerializer serializer = new DataContractJsonSerializer(item.GetType(),settings);
// Remainder as in your question.
但是DateTimeOffset
的结果如下:
{"SaveDate":{"DateTime":"2020-06-04T22:00:00.00+00:00","OffsetMinutes":300}}
这不是您要查找的简单字符串。似乎没有任何记录的方法可以覆盖DateTimeOffset
的序列化格式。演示小提琴#1 here。
自从您写了我要解决的实际问题是,让DataContractJsonSerializer序列化的数据通过JsonConvert DeserialzeObject方法反序列化,将Json.NET配置为反序列化DataContractJsonSerializer
格式。首先,定义以下自定义JsonConverter
:
public class DataContractDateTimeOffsetConverter : JsonConverter
{
readonly bool canWrite;
public DataContractDateTimeOffsetConverter() : this(true) { }
public DataContractDateTimeOffsetConverter(bool canWrite) => this.canWrite = canWrite;
public override bool CanWrite => canWrite;
public override bool CanConvert(Type objectType) => objectType == typeof(DateTimeOffset) || objectType == typeof(DateTimeOffset?);
[JsonObject(NamingStrategyType = typeof(DefaultNamingStrategy))] // Ignore camel casing
class DateTimeOffsetDTO<TOffset> where TOffset : struct,IComparable,IFormattable
{
public DateTime DateTime { get; set; }
public TOffset OffsetMinutes { get; set; }
}
public override void WriteJson(JsonWriter writer,object value,JsonSerializer serializer)
{
var input = (DateTimeOffset)value;
var oldDateFormatHandling = writer.DateFormatHandling;
var oldDateTimeZoneHandling = writer.DateTimeZoneHandling;
try
{
writer.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
writer.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
var offsetMinutes = input.Offset.TotalMinutes;
var offsetMinutesInt = checked((int)offsetMinutes);
var dateTime = input.DateTime.AddMinutes(-input.Offset.TotalMinutes);
if (offsetMinutesInt == offsetMinutes) // An integer number of mintues
serializer.Serialize(writer,new DateTimeOffsetDTO<int> { DateTime = dateTime,OffsetMinutes = offsetMinutesInt });
else
serializer.Serialize(writer,new DateTimeOffsetDTO<double> { DateTime = dateTime,OffsetMinutes = offsetMinutes });
}
finally
{
writer.DateFormatHandling = oldDateFormatHandling;
writer.DateTimeZoneHandling = oldDateTimeZoneHandling;
}
}
public override object ReadJson(JsonReader reader,Type objectType,object existingValue,JsonSerializer serializer)
{
switch (reader.MoveToContentAndAssert().TokenType)
{
// note that if there is a possibility of getting ISO 8601 strings for DateTimeOffset as well as complex objects,you may need to configure
// JsonSerializerSettings.DateParseHandling = DateParseHandling.None or DateParseHandling.DateTimeOffset at a higher code level to
// avoid premature deserialization as DateTime by JsonTextReader.
case JsonToken.String:
case JsonToken.Date:
return (DateTimeOffset)JToken.Load(reader);
case JsonToken.StartObject:
var old = reader.DateTimeZoneHandling;
try
{
reader.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
var dto = serializer.Deserialize<DateTimeOffsetDTO<double>>(reader);
var result = new DateTimeOffset(new DateTime(dto.DateTime.AddMinutes(dto.OffsetMinutes).Ticks,DateTimeKind.Unspecified),TimeSpan.FromMinutes(dto.OffsetMinutes));
return result;
}
finally
{
reader.DateTimeZoneHandling = old;
}
case JsonToken.Null:
return null;
default:
throw new JsonSerializationException(); // Unknown token
}
}
}
public static partial class JsonExtensions
{
public static JsonReader MoveToContentAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (reader.TokenType == JsonToken.None) // Skip past beginning of stream.
reader.ReadAndAssert();
while (reader.TokenType == JsonToken.Comment) // Skip past comments.
reader.ReadAndAssert();
return reader;
}
public static JsonReader ReadAndAssert(this JsonReader reader)
{
if (reader == null)
throw new ArgumentNullException();
if (!reader.Read())
throw new JsonReaderException("Unexpected end of JSON stream.");
return reader;
}
}
现在,您可以通过将转换器添加到JsonSerializerSettings.Converters
来反序列化DataContractJsonSerializer
生成的JSON:
var settings = new JsonSerializerSettings
{
Converters = { new DataContractDateTimeOffsetConverter(true) },};
var item = JsonConvert.DeserializeObject<TestToSeailize>(json,settings);
注意:
-
如果不想以DataContractJsonSerializer
格式进行序列化,请将canWrite : false
传递给转换器的构造函数。
-
如果有可能获得ISO 8601字符串以及DateTimeOffset
值的复杂对象,则可能需要以更高的代码级别配置JsonSerializerSettings.DateParseHandling = DateParseHandling.None
或DateParseHandling.DateTimeOffset
以避免DateTime
将ISO 8601字符串过早反序列化为JsonTextReader
对象。
演示小提琴#2 here。
本文链接:https://www.f2er.com/2037538.html