【问题标题】:parsing a datetime with timezone to DateTimeOffset behaves differently according to the machine local settings根据机器本地设置,将带有时区的日期时间解析为 DateTimeOffset 的行为会有所不同
【发布时间】:2021-04-26 23:09:19
【问题描述】:

使用此日期调用 api:

2021-01-09T21:13:00 +00:00

2021-01-09T21:13:00 +01:00

根据机器的本地设置,我将此日期转换为以不同方式转换的 api,是否可以隔离此行为并始终在 UTC 时区获取日期?

public class Movimento
    {
        public int Id { get; set; }
        [JsonConverter(typeof(ExperimentalConverter))]
        public DateTimeOffset MyDate { get; set; }
        .......

}



public class ExperimentalConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return objectType == typeof(DateTimeOffset) || objectType == typeof(DateTime);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        /*
                =============IF MY MACHINE LOCAL TIME IS SET TO UTC + 01:00  ========================
                i got "09/01/2021 21:13:00" -->  when the client call the api passing --> "2021-01-09T21:13:00+01:00"
                i got "09/01/2021 22:13:00" -->  when the client call the api passing --> "2021-01-09T21:13:00+00:00"

                 =============IF MY MACHINE LOCAL TIME IS SET TO UTC (UTC +  00:00)  ========================
                i got "09/01/2021 20:13:00" -->  when the client call the api passing --> "2021-01-09T21:13:00+01:00"
                i got "09/01/2021 21:13:00" -->  when the client call the api passing --> "2021-01-09T21:13:00+00:00"
         */
        var parsedData = (DateTime)reader.Value;   // 09/01/2021 21:13:00  when the api pass "2021-01-09T21:13:00+01:00"

        //i need a way to uderstad if the received date is in UTC format or UTC+01:00 indipendently from the local settings of the machine, so i can later riapply the offset i need 
        //"parsedData.Kind" give me always the value Local (because the date in this method is already translates according to the local settings of the machine 
        
        .......
    }

【问题讨论】:

  • DateTimeOffsetDateTime 的转换似乎总是使用未指定的 DateTimeKind,这使得它最终格式化为本地。如果阅读器将该值存储为DateTimeOffset,那么您应该将其转换为该值,然后使用UtcDateTime 属性将其保持为UTC(如果您正在尝试这样做)。 DateTime/DateTimeOffset这些年来的选角行为让我很头疼。
  • @MartinCostello (DateTimeOffset)reader.Value 给我错误,所以我尝试DateTimeOffset.Parse(reader.Value.ToString()); 这样是不是时区丢失了?
  • 对于Parse(),您应该使用采用DateTimeStyles 值的重载。然后您可以控制时区的处理方式(例如DateTimeStyles.AdjustToUniversal):docs.microsoft.com/en-us/dotnet/api/…

标签: c# json.net timezone utc datetimeoffset


【解决方案1】:

通常当您解析DateTimeOffset 时,偏移量将被保留。但不幸的是,当您将JsonConverter 应用于DateTimeOffset 属性时,reader.Value 将(使用默认设置)包含一个DateTime,其中偏移量已经受到计算机本地时区的影响。

要解决此问题,请在序列化设置中设置 DateParseHandling.DateTimeOffset

JsonConvert.DefaultSettings = () => new JsonSerializerSettings
{
    DateParseHandling = DateParseHandling.DateTimeOffset
};

然后reader.Value 将包含一个DateTimeOffset,您可以将其拆箱。

另外,您可以使用JsonConverter<T> 来简化您的代码,并且您不需要处理DateTime 解析(除非您的问题中没有描述其他要求)。

public class UtcDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
    public override DateTimeOffset ReadJson(JsonReader reader, Type objectType, DateTimeOffset existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        // First get the DateTimeOffset exactly as presented (asserting never-null)
        var value = (DateTimeOffset) reader.Value!;

        // Then convert it to UTC before returning it.
        return value.ToUniversalTime();
    }

    public override void WriteJson(JsonWriter writer, DateTimeOffset value, JsonSerializer serializer)
    {
        // Convert the value to UTC and write it to JSON using a Z suffix
        writer.WriteValue(value.UtcDateTime);      
    }
}

我还为您提供了一个对这类事情有意义的 WriteJson 实现,在输出 JSON 中使用 Z 而不是 +00:00

Working example here.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    • 2022-01-10
    相关资源
    最近更新 更多