【问题标题】:System.FormatException: The JSON value is not in a supported DateTimeOffset formatSystem.FormatException:JSON 值不是支持的 DateTimeOffset 格式
【发布时间】:2021-06-06 08:10:58
【问题描述】:

我正在阅读有关 DateTime 相关格式支持的 MSDocs 文章 https://docs.microsoft.com/en-us/dotnet/standard/datetime/system-text-json-support#support-for-the-iso-8601-12019-format

我试图四处寻找,只是为了弄清楚默认配置没有按预期工作,或者我一定遗漏了一些东西。

我的意思是:

DateTimeOffset.Parse("2021-03-17T12:03:14+0000");

工作得很好。

但是

JsonSerializer.Deserialize<TestType>(@"{ ""CreationDate"": ""2021-03-17T12:03:14+0000"" }");

没有。

例子:

using System;
using System.Text.Json;
using System.Threading.Tasks;


namespace CSharpPlayground
{
    public record TestType(DateTimeOffset CreationDate);
    
    public static class Program
    {
        public static void Main()
        {
            var dto = DateTimeOffset.Parse("2021-03-17T12:03:14+0000");
            Console.WriteLine(dto);

            var testType = JsonSerializer.Deserialize<TestType>(@"{ ""CreationDate"": ""2021-03-17T12:03:14+0000"" }");
            Console.WriteLine(testType.CreationDate);
        }
    }
}

抛出以下异常:

System.Text.Json.JsonException: The JSON value could not be converted to CSharpPlayground.TestType. Path: $.CreationDate | LineNumber: 0 | BytePositionInLine: 44.
 ---> System.FormatException: The JSON value is not in a supported DateTimeOffset format.

【问题讨论】:

  • 请不要在您的问题标题中添加标签(标签帮助部分对此非常明确,并且会列出您不应该使用的示例格式)。
  • 我预计问题出在 +0000 上,预期值为 +00:00。我不能建议如何解决这个问题,因为我对 System.Text.Json 不是很熟悉,但它可能涉及编写自定义转换器。我发现了一个与此here 相关的 GitHub 问题
  • @Llama 感谢您指出这一点,抱歉。
  • 仅供参考,当您在时间戳中使用连字符和冒号时,ISO 8601 将其称为“扩展”格式,并且在偏移组件中也需要冒号。 “基本”格式不在 任何 组件中使用连字符或冒号。规范不允许将两者混合,因此此处显示的字符串不符合 ISO 8601。
  • @MattJohnson-Pint 仅供参考,这来自我必须处理的 PSP,我无法决定他们如何实现他们的 API……而且它远不是唯一的问题。我对我必须在工作中使用哪个 PSP 没有发言权。 “瞧”

标签: c# json .net datetimeoffset system.text.json


【解决方案1】:

使用System.Text.Json 实现自定义 JSON 行为通常使用自定义转换器完成。不幸的是,针对不同日期格式的开箱即用的工具并不多,因此如果您需要反序列化不是默认 ISO 8601-1:2019 格式的内容,您需要自己动手。

幸运的是,这并不难:

   using System.Text.Json;
   using System.Text.Json.Serialization;

    public class DateTimeOffsetConverterUsingDateTimeParse : JsonConverter<DateTimeOffset >
    {
        public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
        {
            Debug.Assert(typeToConvert == typeof(DateTimeOffset));
            return DateTimeOffset .Parse(reader.GetString());
        }

        public override void Write(Utf8JsonWriter writer, DateTimeOffset  value, JsonSerializerOptions options)
        {
            writer.WriteStringValue(value.ToString());
        }
    }
    

这样您的行为与使用 DateTimeOffset.Parse() 时的行为相同。

你可以这样使用它

    public record TestType(DateTimeOffset CreationDate);
    public class Program
    {
        public static void Main(string[] args)
        {
            JsonSerializerOptions options = new JsonSerializerOptions();
            options.Converters.Add(new DateTimeOffsetConverterUsingDateTimeParse());
            
            var testType = JsonSerializer.Deserialize<TestType>(@"{ ""CreationDate"": ""2021-03-17T12:03:14+0000"" }",options);
            Console.WriteLine(testType.CreationDate);
        }
    }
    

【讨论】:

  • 哦,谢谢,我认为我试图解析的格式是标准的一部分,我的错。再次感谢您的回答,非常感谢!
  • 很好的答案,但是您的 Write 方法中存在错误。应该是: public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) { writer.WriteStringValue(value.ToString("O")); }
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-02-12
  • 2016-07-01
  • 1970-01-01
相关资源
最近更新 更多