【问题标题】:Is it possible to specify an offset for JSON.NET deserialization of DateTimeOffset?是否可以为 DateTimeOffset 的 JSON.NET 反序列化指定偏移量?
【发布时间】:2014-05-15 19:03:55
【问题描述】:

以下语句打印“1/1/0001 4:00:00 PM -05:00”

Console.WriteLine(JsonConvert.DeserializeObject<DateTimeOffset>("\"0001-01-01T16:00:00\""));

这是因为当 json.net 将 DateTime 字符串(没有偏移量)反序列化为 DateTimeOffset 对象时,它会分配本地偏移量,在本例中为 -05:00。

如果我不想使用本地偏移量怎么办?有什么方法可以指定用于此反序列化的偏移量?

(用例是数据库服务器和Web服务器在不同的时区,我需要有区域未指定时间的传入请求在反序列化后具有数据库服务器的偏移量。)

更新:我无法控制传入时间字符串的格式。我有一个具有 DateTimeOffset 属性的数据传输对象类,我需要将传入的时间数据存储到该属性中。

【问题讨论】:

    标签: c# json.net datetimeoffset


    【解决方案1】:

    您要反序列化的类型应该与您期望的数据相匹配。如果您不希望包含偏移量,请不要反序列化为DateTimeOffset。相反,反序列化为DateTime。它的.Kind 属性将具有DateTimeKind.Unspecified

    您对 Web 服务器时区的了解与反序列化任务无关。因此,事后单独应用它。

    // deserialize the json
    DateTime dt = JsonConvert.DeserializeObject<DateTime>("\"2014-01-01T00:00:00\"");
    
    // find your target time zone
    TimeZoneInfo tz = TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time");
    
    // apply the time zone to determine the offset, and create the DateTimeOffset
    DateTimeOffset dto = new DateTimeOffset(dt, tz.GetUtcOffset(dt));
    

    更新

    每个 cmets,如果您需要按照您要求的方式进行此转换,您将需要一个自定义 json 转换器。这应该可以解决问题:

    public class CustomDateTimeConverter : IsoDateTimeConverter
    {
        private readonly string defaultTimeZoneId;
    
        public CustomDateTimeConverter(string defaultTimeZoneId)
        {
            this.defaultTimeZoneId = defaultTimeZoneId;
        }
    
        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            if (objectType != typeof (DateTimeOffset) && objectType != typeof (DateTimeOffset?))
                return base.ReadJson(reader, objectType, existingValue, serializer);
    
            var dateText = reader.Value.ToString();
            if (objectType == typeof(DateTimeOffset?) && string.IsNullOrEmpty(dateText))
                return null;
    
            if (dateText.IndexOfAny(new[] { 'Z', 'z', '+'}) == -1 && dateText.Count(c => c == '-') == 2)
            {
                var dt = DateTime.Parse(dateText);
                var tz = TimeZoneInfo.FindSystemTimeZoneById(this.defaultTimeZoneId);
                var offset = tz.GetUtcOffset(dt);
                return new DateTimeOffset(dt, offset);
            }
    
            return DateTimeOffset.Parse(dateText);
        }
    }
    

    然后你可以在转换过程中连接它:

    var settings = new JsonSerializerSettings();
    settings.DateParseHandling = DateParseHandling.None;
    settings.Converters.Add(new CustomDateTimeConverter(defaultTimeZoneId: "Eastern Standard Time"));
    DateTimeOffset dto = JsonConvert.DeserializeObject<DateTimeOffset>("\"2014-01-01T00:00:00\"", settings);
    

    请务必使用有效的时区 ID。不要使用固定的偏移量。

    此外,如果您想在没有日期的情况下打发时间,这将不是正确的方法。这是一个完全不同的问题,传递0001-01-01 作为日期并不是一个好方法。我很乐意与您讨论in chat

    【讨论】:

    • 好吧,问题是,我们必须使用 DateTimeOffset 属性支持两种时间类型,区域未指定和区域特定。
    • 而且我无法更正反序列化的 DateTimeOffset 对象,因为我无法判断该对象是否带有偏移量因此不需要更正,或者它没有偏移量并被分配本地偏移量。
    • 这是您的数据合同的一部分 - 您将支持不明确的输入数据吗?如果是这样,我看不出你会如何轻松解决它。
    • 请记住,没有偏移的输入日期和时间与唯一的时间点不同。由于daylight saving time issues,它可能会模棱两可。
    • 您可以考虑的一种方法是编写自己的 JsonConvert 类。
    【解决方案2】:

    如果原始字符串中有偏移量(-8:00):

    Console.WriteLine(JsonConvert.DeserializeObject<DateTimeOffset>("\"0001-01-01T16:00:00-08:00\""));
    

    如果没有,试试这个

    var dateTime = JsonConvert.DeserializeObject<DateTime>("\"0001-01-01T16:00:00\"");
    DateTimeOffset dto = new DateTimeOffset(dateTime, TimeSpan.FromHours(-8));
    

    【讨论】:

    • 我无法控制传入的时间字符串。对不起,我会补充说明。
    • 尝试解析成DateTime后手动添加偏移量。
    • 我不能。正如我在另一条评论中提到的,无法判断反序列化的 DateTimeOffset 对象是否需要更正。我怎么知道在反序列化过程中是否添加了偏移量,而不是作为传入时间字符串的一部分?
    • 如果 dateTime 上的 Kind 属性是 Local 则表示字符串包含偏移量。
    • 我不确定你的意思。如果传入的时间字符串包含偏移量,则生成的反序列化 DateTimeOffset 对象将包含一个 Kind = Unspecified 的嵌入式 DateTime 对象。如果传入的时间字符串不包含偏移量,那么结果还是一样的,嵌入的 DateTime 对象有 Kind = Unspecified。
    猜你喜欢
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-04-07
    • 1970-01-01
    • 1970-01-01
    • 2011-01-06
    • 1970-01-01
    相关资源
    最近更新 更多