【问题标题】:Formatting DateTime in ASP.NET Core 3.0 using System.Text.Json使用 System.Text.Json 在 ASP.NET Core 3.0 中格式化 DateTime
【发布时间】:2020-01-25 20:52:52
【问题描述】:

我正在将 Web API 从 .NET Core 2.2 迁移到 3.0,并希望使用新的 System.Text.Json。使用Newtonsoft 时,我可以使用下面的代码格式化DateTime。我怎样才能做到这一点?

.AddJsonOptions(options =>
    {
        options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
        options.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ";
    });

【问题讨论】:

  • 真正的问题是什么?即使不是,如何将 DateTime 视为 UTC? JSON.NET 和 System.Text.Json 默认使用 ISO8601。如果 DateTimeKind 是 UTC,则将 Z 附加到字符串中。本地时间将包括本地时区偏移
  • 这不是您的代码所做的,因为 JSON.NET 已经使用 ISO8601 - 您使用的格式相同。你在那里所做的是强制它对所有DateTime kinds 使用UTC。我已经解释过 System.Text.Json 已经 处理 DateTime.Kind 是 UTC 的日期。这意味着您要存储的日期是本地的或未指定的。
  • 你为什么要转换为 UTC?为什么不让 System.Text.Json 发出偏移量?在任何情况下,日期格式都在DateTime and DateTimeOffset support in System.Text.Json 中进行了说明。除了创建自定义格式化程序之外,没有办法强制格式化。您可以确保您使用的所有日期都是 UTC 或使用 DateTimeOffset 来确保指定偏移量
  • 我想序列化没有小数秒的 DateTime,并且总是 UTC。使用 swift(iOS 应用)访问我的 API 时,小数秒和偏移量会导致 json 解析失败。
  • 相关问题在这里:github.com/dotnet/runtime/issues/1566

标签: c# json datetime asp.net-core system.text.json


【解决方案1】:

使用自定义格式化程序解决。感谢 Panagiotis 的建议。

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

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"));
    }
}


// in the ConfigureServices()
services.AddControllers()
    .AddJsonOptions(options =>
     {
         options.JsonSerializerOptions.Converters.Add(new DateTimeConverter());
     });

【讨论】:

  • 这段代码有两个问题。 1) NewtonSoft.Json 并不总是在价值上调用.ToUniversalTime()。这取决于它的DateTimeKind。提供的格式字符串去除了NewtonSoft.Json 所保留的 7 位小数精度。如果您同意,我可以用正确的代码更新您的答案。否则我可以用正确的代码创建一个新的答案。
  • 问题是关于 System.Text.Json 而不是 NewtonSoft.Json
  • 因为我已经在客户端代码中使用了 UTC,所以我排除了 ToUniversalTime(),我所需要的只是日期字符串末尾的 Z,这样就完成了,这是正确的我猜的方法?!显然reader 有一个方法reader.GetDateTime() 可以在Read 方法中使用
  • 15 行代码,Startup 中的一个脆弱修改,只是为了在我的 API 输出中有一个完整明确的日期。这会影响可信度。
  • 注意时区! 上面的代码将假定您的 C# DateTime 是本地时间,并在序列化为 UTC 之前将其转换为 UTC。如果为了保持理智,您的所有日期都已经是 UTC,则在此步骤中将潜入不需要的时区增量。 (要解决此问题,只需在 Write() 方法中删除 ToUniversalTime()。)
【解决方案2】:

迁移到 Core 3 我必须替换 System.Text.Json 才能再次使用 Newtonsoft:

services.AddControllers().AddNewtonsoftJson();

但我在 Angular 应用程序中遇到了与 UTC 日期相同的问题,我必须添加它以获取 UTC 日期:

services.AddControllers().AddNewtonsoftJson(
       options => options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc);

在你的情况下,你应该能够做到这一点:

services.AddControllers().AddNewtonsoftJson(options =>
    {
        options.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
        options.SerializerSettings.DateFormatString = "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ";
    });

它有效,我希望它有帮助......

【讨论】:

  • 问题与 newtonsoft.json 无关
  • 这是解决问题的好方法。谢谢伙计,你拯救了我的一天。
  • 我会接受这个答案,kk。谢谢
【解决方案3】:

当您看到dumpster fire of Date.Parse() and Date.ParseExact() 时,asp.net 核心日期序列化/deserialization 的垃圾箱大火可能更容易理解。我们在 javascript 之间传递日期,所以我们不想格式化。我们只想transparently serialize and deserialize between DateTime and ISO 8601 in UTC

这不是默认设置,并且没有简单的配置选项,而且解决方案如此时髦和脆弱,这会破坏信誉。这是目前对我有用的,基于D.English's answer 用于写作,链接答案用于阅读,并使用this answer 正确访问 JsonDocument...

// in Startup.cs ConfigureServices()

services.AddMvc().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.Converters.Add(new UtcDateTimeConverter());
});


public class BobbyUtcDateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        Debug.Assert(typeToConvert == typeof(DateTime));
        using (var jsonDoc = JsonDocument.ParseValue(ref reader))
        {
            return DateTime.SpecifyKind(
                DateTime.Parse(jsonDoc.RootElement.GetRawText().Trim('"').Trim('\'')),
                DateTimeKind.Utc
            );
        }
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToString("yyyy-MM-ddTHH:mm:ss.fffZ", System.Globalization.CultureInfo.InvariantCulture));
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-14
    • 2020-12-13
    • 2011-03-28
    相关资源
    最近更新 更多