System.Text.Json 库根据 ISO 8601-1:2019 扩展配置文件分析和写入 DateTime DateTimeOffset 值。 对于使用 JsonSerializer 进行序列化和反序列化, 转换器 提供自定义支持。 还可以使用 Utf8JsonReader Utf8JsonWriter 实现自定义支持。

支持 ISO 8601-1:2019 格式

JsonSerializer Utf8JsonReader Utf8JsonWriter JsonElement 类型根据 ISO 8601-1:2019 格式的扩展配置文件分析和写入 DateTime DateTimeOffset 文本表示形式。 例如, 2019-07-26T16:59:57-05:00

DateTime DateTimeOffset 数据可使用 JsonSerializer 进行序列化:

using System.Text.Json; public class Example private class Product public string? Name { get; set; } public DateTime ExpiryDate { get; set; } public static void Main(string[] args) Product p = new Product(); p.Name = "Banana"; p.ExpiryDate = new DateTime(2019, 7, 26); string json = JsonSerializer.Serialize(p); Console.WriteLine(json); // The example displays the following output: // {"Name":"Banana","ExpiryDate":"2019-07-26T00:00:00"}

DateTime DateTimeOffset 还可以使用 JsonSerializer 进行反序列化:

using System.Text.Json; public class Example private class Product public string? Name { get; set; } public DateTime ExpiryDate { get; set; } public static void Main(string[] args) string json = @"{""Name"":""Banana"",""ExpiryDate"":""2019-07-26T00:00:00""}"; Product p = JsonSerializer.Deserialize<Product>(json)!; Console.WriteLine(p.Name); Console.WriteLine(p.ExpiryDate); // The example displays output similar to the following: // Banana // 7/26/2019 12:00:00 AM

使用默认选项时,输入 DateTime DateTimeOffset 文本表示形式必须符合 ISO 8601-1:2019 扩展配置文件。 尝试反序列化不符合配置文件的表示形式将导致 JsonSerializer 引发 JsonException

using System.Text.Json; public class Example private class Product public string? Name { get; set; } public DateTime ExpiryDate { get; set; } public static void Main(string[] args) string json = @"{""Name"":""Banana"",""ExpiryDate"":""26/07/2019""}"; Product _ = JsonSerializer.Deserialize<Product>(json)!; catch (JsonException e) Console.WriteLine(e.Message); // The example displays the following output: // The JSON value could not be converted to System.DateTime. Path: $.ExpiryDate | LineNumber: 0 | BytePositionInLine: 42.

JsonDocument 提供对 JSON 有效负载内容的结构化访问,包括 DateTime DateTimeOffset 表示形式。 以下示例演示如何通过一组温度计算周一的平均温度:

using System.Text.Json; public class Example private static double ComputeAverageTemperatures(string json) JsonDocumentOptions options = new JsonDocumentOptions AllowTrailingCommas = true using (JsonDocument document = JsonDocument.Parse(json, options)) int sumOfAllTemperatures = 0; int count = 0; foreach (JsonElement element in document.RootElement.EnumerateArray()) DateTimeOffset date = element.GetProperty("date").GetDateTimeOffset(); if (date.DayOfWeek == DayOfWeek.Monday) int temp = element.GetProperty("temp").GetInt32(); sumOfAllTemperatures += temp; count++; double averageTemp = (double)sumOfAllTemperatures / count; return averageTemp; public static void Main(string[] args) string json = @"[" + @"{" + @"""date"": ""2013-01-07T00:00:00Z""," + @"""temp"": 23," + @"}," + @"{" + @"""date"": ""2013-01-08T00:00:00Z""," + @"""temp"": 28," + @"}," + @"{" + @"""date"": ""2013-01-14T00:00:00Z""," + @"""temp"": 8," + @"}," + @"]"; Console.WriteLine(ComputeAverageTemperatures(json)); // The example displays the following output: // 15.5

假定有效负载的 DateTime 表示形式不合规,尝试计算平均温度将导致 JsonDocument 引发 FormatException

using System.Text.Json; public class Example private static double ComputeAverageTemperatures(string json) JsonDocumentOptions options = new JsonDocumentOptions AllowTrailingCommas = true using (JsonDocument document = JsonDocument.Parse(json, options)) int sumOfAllTemperatures = 0; int count = 0; foreach (JsonElement element in document.RootElement.EnumerateArray()) DateTimeOffset date = element.GetProperty("date").GetDateTimeOffset(); if (date.DayOfWeek == DayOfWeek.Monday) int temp = element.GetProperty("temp").GetInt32(); sumOfAllTemperatures += temp; count++; double averageTemp = (double)sumOfAllTemperatures / count; return averageTemp; public static void Main(string[] args) // Computing the average temperatures will fail because the DateTimeOffset // values in the payload do not conform to the extended ISO 8601-1:2019 profile. string json = @"[" + @"{" + @"""date"": ""2013/01/07 00:00:00Z""," + @"""temp"": 23," + @"}," + @"{" + @"""date"": ""2013/01/08 00:00:00Z""," + @"""temp"": 28," + @"}," + @"{" + @"""date"": ""2013/01/14 00:00:00Z""," + @"""temp"": 8," + @"}," + @"]"; Console.WriteLine(ComputeAverageTemperatures(json)); // The example displays the following output: // Unhandled exception.System.FormatException: One of the identified items was in an invalid format. // at System.Text.Json.JsonElement.GetDateTimeOffset()

较低级别的 Utf8JsonWriter 写入 DateTime DateTimeOffset 数据:

using System.Text; using System.Text.Json; public class Example public static void Main(string[] args) JsonWriterOptions options = new JsonWriterOptions Indented = true using (MemoryStream stream = new MemoryStream()) using (Utf8JsonWriter writer = new Utf8JsonWriter(stream, options)) writer.WriteStartObject(); writer.WriteString("date", DateTimeOffset.UtcNow); writer.WriteNumber("temp", 42); writer.WriteEndObject(); string json = Encoding.UTF8.GetString(stream.ToArray()); Console.WriteLine(json); // The example output similar to the following: // "date": "2019-07-26T00:00:00+00:00", // "temp": 42

Utf8JsonReader 分析 DateTime DateTimeOffset 数据:

using System.Text; using System.Text.Json; public class Example public static void Main(string[] args) byte[] utf8Data = Encoding.UTF8.GetBytes(@"""2019-07-26T00:00:00"""); Utf8JsonReader json = new Utf8JsonReader(utf8Data); while (json.Read()) if (json.TokenType == JsonTokenType.String) Console.WriteLine(json.TryGetDateTime(out DateTime datetime)); Console.WriteLine(datetime); Console.WriteLine(json.GetDateTime()); // The example displays output similar to the following: // True // 7/26/2019 12:00:00 AM // 7/26/2019 12:00:00 AM

尝试使用 Utf8JsonReader 读取不合规的格式将导致引发 FormatException

using System.Text; using System.Text.Json; public class Example public static void Main(string[] args) byte[] utf8Data = Encoding.UTF8.GetBytes(@"""2019/07/26 00:00:00"""); Utf8JsonReader json = new Utf8JsonReader(utf8Data); while (json.Read()) if (json.TokenType == JsonTokenType.String) Console.WriteLine(json.TryGetDateTime(out DateTime datetime)); Console.WriteLine(datetime); DateTime _ = json.GetDateTime(); // The example displays the following output: // False // 1/1/0001 12:00:00 AM // Unhandled exception. System.FormatException: The JSON value is not in a supported DateTime format. // at System.Text.Json.Utf8JsonReader.GetDateTime()

将 DateOnly 和 TimeOnly 属性序列化

在 .NET 7+ 中, System.Text.Json 支持将 DateOnly TimeOnly 类型序列化和反序列化。 请考虑以下对象:

sealed file record Appointment( Guid Id, string Description, DateOnly Date, TimeOnly StartTime, TimeOnly EndTime);

以下示例序列化 Appointment 对象,显示生成的 JSON,然后将其反序列化为 Appointment 类型的新实例。 最后,对比原始实例与反序列化后的新实例是否相同,并将结果写入控制台:

Appointment originalAppointment = new( Id: Guid.NewGuid(), Description: "Take dog to veterinarian.", Date: new DateOnly(2002, 1, 13), StartTime: new TimeOnly(5,15), EndTime: new TimeOnly(5, 45)); string serialized = JsonSerializer.Serialize(originalAppointment); Console.WriteLine($"Resulting JSON: {serialized}"); Appointment deserializedAppointment = JsonSerializer.Deserialize<Appointment>(serialized)!; bool valuesAreTheSame = originalAppointment == deserializedAppointment; Console.WriteLine($""" Original record has the same values as the deserialized record: {valuesAreTheSame} """);

在上述代码中:

  • Appointment 对象实例化并分配给 appointment 变量。
  • 使用 JsonSerializer.Serialize appointment 实例序列化为 JSON。
  • 将生成的 JSON 写入控制台。
  • 使用 JsonSerializer.Deserialize 将 JSON 反序列化为 Appointment 类型的新实例。
  • 对比原始实例与反序列化后的新实例是否相同。
  • 将对比结果写入控制台。
  • DateTime DateTimeOffset 的自定义支持

    使用 JsonSerializer

    如果希望序列化程序执行自定义分析或格式设置,可以实现 自定义转换器 。 以下是一些示例:

    使用 DateTime(Offset).Parse 和 DateTime(Offset).ToString

    如果无法确定输入 DateTime DateTimeOffset 文本表示形式的格式,可在转换器读取逻辑中使用 DateTime(Offset).Parse 方法。 此方法使你能够使用 .NET 的广泛支持来分析各种 DateTime DateTimeOffset 文本格式,包括不符合 ISO 8601-1:2019 扩展配置文件的非 ISO 8601 字符串和 ISO 8601 格式。 与使用序列化程序的本机实现相比,此方法的性能较低。

    若要序列化,可在转换器写入逻辑中使用 DateTime(Offset).ToString 方法。 此方法使你能够使用任何 标准日期和时间格式 以及 自定义日期和时间格式 来写入 DateTime DateTimeOffset 值。 与使用序列化程序的本机实现相比,此方法的性能也较低。

    using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; namespace DateTimeConverterExamples; public class DateTimeConverterUsingDateTimeParse : JsonConverter<DateTime> public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) Debug.Assert(typeToConvert == typeof(DateTime)); return DateTime.Parse(reader.GetString() ?? string.Empty); public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) writer.WriteStringValue(value.ToString()); class Program private static void ParseDateTimeWithDefaultOptions() DateTime _ = JsonSerializer.Deserialize<DateTime>(@"""04-10-2008 6:30 AM"""); private static void FormatDateTimeWithDefaultOptions() Console.WriteLine(JsonSerializer.Serialize(DateTime.Parse("04-10-2008 6:30 AM -4"))); private static void ProcessDateTimeWithCustomConverter() JsonSerializerOptions options = new JsonSerializerOptions(); options.Converters.Add(new DateTimeConverterUsingDateTimeParse()); string testDateTimeStr = "04-10-2008 6:30 AM"; string testDateTimeJson = @"""" + testDateTimeStr + @""""; DateTime resultDateTime = JsonSerializer.Deserialize<DateTime>(testDateTimeJson, options); Console.WriteLine(resultDateTime); string resultDateTimeJson = JsonSerializer.Serialize(DateTime.Parse(testDateTimeStr), options); Console.WriteLine(Regex.Unescape(resultDateTimeJson)); static void Main(string[] args) // Parsing non-compliant format as DateTime fails by default. ParseDateTimeWithDefaultOptions(); catch (JsonException e) Console.WriteLine(e.Message); // Formatting with default options prints according to extended ISO 8601 profile. FormatDateTimeWithDefaultOptions(); // Using converters gives you control over the serializers parsing and formatting. ProcessDateTimeWithCustomConverter(); // The example displays output similar to the following: // The JSON value could not be converted to System.DateTime. Path: $ | LineNumber: 0 | BytePositionInLine: 20. // "2008-04-10T06:30:00-04:00" // 4/10/2008 6:30:00 AM // "4/10/2008 6:30:00 AM"

    实现 JsonConverter<T> T DateTime 时, typeToConvert 参数将始终为 typeof(DateTime) 。 在处理多态情况以及使用泛型以高效方式获取 typeof(T) 时,该参数非常有用。

    使用 Utf8Parser Utf8Formatter

    如果输入 DateTime DateTimeOffset 文本表示形式符合“R”、“l”、“O”或“G” 标准日期和时间格式字符串 之一,或者希望根据其中一种格式进行编写,可以在转换器逻辑中使用基于 UTF-8 的分析和格式设置方法。 此方法比使用 DateTime(Offset).Parse DateTime(Offset).ToString 快得多。

    以下示例演示自定义转换器根据 “R”标准格式 序列化和反序列化 DateTime 值:

    using System.Buffers; using System.Buffers.Text; using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; namespace DateTimeConverterExamples; // This converter reads and writes DateTime values according to the "R" standard format specifier: // https://learn.microsoft.com/dotnet/standard/base-types/standard-date-and-time-format-strings#the-rfc1123-r-r-format-specifier. public class DateTimeConverterForCustomStandardFormatR : JsonConverter<DateTime> public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) Debug.Assert(typeToConvert == typeof(DateTime)); if (Utf8Parser.TryParse(reader.ValueSpan, out DateTime value, out _, 'R')) return value; throw new FormatException(); public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) // The "R" standard format will always be 29 bytes. Span<byte> utf8Date = new byte[29]; bool result = Utf8Formatter.TryFormat(value, utf8Date, out _, new StandardFormat('R')); Debug.Assert(result); writer.WriteStringValue(utf8Date); class Program private static void ParseDateTimeWithDefaultOptions() DateTime _ = JsonSerializer.Deserialize<DateTime>(@"""Thu, 25 Jul 2019 13:36:07 GMT"""); private static void ProcessDateTimeWithCustomConverter() JsonSerializerOptions options = new JsonSerializerOptions(); options.Converters.Add(new DateTimeConverterForCustomStandardFormatR()); string testDateTimeStr = "Thu, 25 Jul 2019 13:36:07 GMT"; string testDateTimeJson = @"""" + testDateTimeStr + @""""; DateTime resultDateTime = JsonSerializer.Deserialize<DateTime>(testDateTimeJson, options); Console.WriteLine(resultDateTime); Console.WriteLine(JsonSerializer.Serialize(DateTime.Parse(testDateTimeStr), options)); static void Main(string[] args) // Parsing non-compliant format as DateTime fails by default. ParseDateTimeWithDefaultOptions(); catch (JsonException e) Console.WriteLine(e.Message); // Using converters gives you control over the serializers parsing and formatting. ProcessDateTimeWithCustomConverter(); // The example displays output similar to the following: // The JSON value could not be converted to System.DateTime.Path: $ | LineNumber: 0 | BytePositionInLine: 31. // 7/25/2019 1:36:07 PM // "Thu, 25 Jul 2019 09:36:07 GMT"

    “R”标准格式的长度始终为 29 个字符。

    “l”(“L”的小写形式)格式未记录为其他 标准日期和时间格式字符串 ,因为只有 Utf8Parser Utf8Formatter 类型支持该格式。 该格式为小写的 RFC 1123(“R”格式的小写版本)。 例如“thu, 25 jul 2019 06:36:07 gmt”。

    使用 DateTime(Offset).Parse 作为序列化程序的本机分析的回退

    如果通常希望输入 DateTime DateTimeOffset 数据以符合 ISO 8601-1:2019 扩展配置文件,可以使用序列化程序的本机分析逻辑。 还可以实现回退机制。 以下示例显示在未能使用 TryGetDateTime(DateTime) 分析 DateTime 文本表示形式后,转换器使用 Parse(String) 成功分析该数据:

    using System.Diagnostics; using System.Text.Json; using System.Text.Json.Serialization; using System.Text.RegularExpressions; namespace DateTimeConverterExamples; public class DateTimeConverterUsingDateTimeParseAsFallback : JsonConverter<DateTime> public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) Debug.Assert(typeToConvert == typeof(DateTime)); if (!reader.TryGetDateTime(out DateTime value)) value = DateTime.Parse(reader.GetString()!); return value; public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) writer.WriteStringValue(value.ToString("dd/MM/yyyy")); class Program private static void ParseDateTimeWithDefaultOptions() DateTime _ = JsonSerializer.Deserialize<DateTime>(@"""2019-07-16 16:45:27.4937872+00:00"""); private static void ProcessDateTimeWithCustomConverter() JsonSerializerOptions options = new JsonSerializerOptions(); options.Converters.Add(new DateTimeConverterUsingDateTimeParseAsFallback()); string testDateTimeStr = "2019-07-16 16:45:27.4937872+00:00"; string testDateTimeJson = @"""" + testDateTimeStr + @""""; DateTime resultDateTime = JsonSerializer.Deserialize<DateTime>(testDateTimeJson, options); Console.WriteLine(resultDateTime); string resultDateTimeJson = JsonSerializer.Serialize(DateTime.Parse(testDateTimeStr), options); Console.WriteLine(Regex.Unescape(resultDateTimeJson)); static void Main(string[] args) // Parsing non-compliant format as DateTime fails by default. ParseDateTimeWithDefaultOptions(); catch (JsonException e) Console.WriteLine(e.Message); // Using converters gives you control over the serializers parsing and formatting. ProcessDateTimeWithCustomConverter(); // The example displays output similar to the following: // The JSON value could not be converted to System.DateTime.Path: $ | LineNumber: 0 | BytePositionInLine: 35. // 7/16/2019 4:45:27 PM // "16/07/2019"

    使用 Unix epoch 日期格式

    以下转换器将处理 Unix epoch 格式,而无论是否带有时区偏移( /Date(1590863400000-0700)/ /Date(1590863400000)/ 之类的值):

    sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset> static readonly DateTimeOffset s_epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero); static readonly Regex s_regex = new Regex("^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$", RegexOptions.CultureInvariant); public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) string formatted = reader.GetString()!; Match match = s_regex.Match(formatted); !match.Success || !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime) || !int.TryParse(match.Groups[3].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours) || !int.TryParse(match.Groups[4].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes)) throw new JsonException(); int sign = match.Groups[2].Value[0] == '+' ? 1 : -1; TimeSpan utcOffset = new TimeSpan(hours * sign, minutes * sign, 0); return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset); public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds); TimeSpan utcOffset = value.Offset; string formatted = FormattableString.Invariant($"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/"); writer.WriteStringValue(formatted); sealed class UnixEpochDateTimeConverter : JsonConverter<DateTime> static readonly DateTime s_epoch = new DateTime(1970, 1, 1, 0, 0, 0); static readonly Regex s_regex = new Regex("^/Date\\(([+-]*\\d+)\\)/$", RegexOptions.CultureInvariant); public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) string formatted = reader.GetString()!; Match match = s_regex.Match(formatted); !match.Success || !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)) throw new JsonException(); return s_epoch.AddMilliseconds(unixTime); public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds); string formatted = FormattableString.Invariant($"/Date({unixTime})/"); writer.WriteStringValue(formatted);

    使用 Utf8JsonWriter 编写时

    如果要使用 Utf8JsonWriter 编写自定义 DateTime DateTimeOffset 文本表示形式,可以将自定义表示形式的格式设置为 String ReadOnlySpan<Byte> ReadOnlySpan<Char> JsonEncodedText ,然后将它传递给相应的 Utf8JsonWriter.WriteStringValue Utf8JsonWriter.WriteString 方法。

    以下示例演示如何使用 ToString(String, IFormatProvider) 创建自定义 DateTime 格式,然后如何使用 WriteStringValue(String) 方法编写该格式:

    using System.Globalization; using System.Text; using System.Text.Json; public class Example public static void Main(string[] args) var options = new JsonWriterOptions Indented = true using (var stream = new MemoryStream()) using (var writer = new Utf8JsonWriter(stream, options)) string dateStr = DateTime.UtcNow.ToString("F", CultureInfo.InvariantCulture); writer.WriteStartObject(); writer.WriteString("date", dateStr); writer.WriteNumber("temp", 42); writer.WriteEndObject(); string json = Encoding.UTF8.GetString(stream.ToArray()); Console.WriteLine(json); // The example displays output similar to the following: // "date": "Tuesday, 27 August 2019 19:21:44", // "temp": 42

    使用 Utf8JsonReader 读取时

    如果要使用 Utf8JsonReader 读取自定义 DateTime DateTimeOffset 文本表示形式,可使用 GetString() 方法将当前 JSON 令牌的值获取为 String ,然后使用自定义逻辑分析该值。

    以下示例演示如何使用 GetString() 方法检索自定义 DateTimeOffset 文本表示形式,然后使用 ParseExact(String, String, IFormatProvider) 进行分析:

    using System.Globalization; using System.Text; using System.Text.Json; public class Example public static void Main(string[] args) byte[] utf8Data = Encoding.UTF8.GetBytes(@"""Friday, 26 July 2019 00:00:00"""); var json = new Utf8JsonReader(utf8Data); while (json.Read()) if (json.TokenType == JsonTokenType.String) string value = json.GetString(); DateTimeOffset dto = DateTimeOffset.ParseExact(value, "F", CultureInfo.InvariantCulture); Console.WriteLine(dto); // The example displays output similar to the following: // 7/26/2019 12:00:00 AM -04:00

    System.Text.Json 中的 ISO 8601-1:2019 扩展配置文件

    日期和时间组件

    System.Text.Json 中实现的 ISO 8601-1:2019 扩展配置文件定义了日期和时间表示形式的以下组件。 这些组件用于定义在分析和格式化 DateTime DateTimeOffset 表示形式时支持的各种粒度级别。

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss"( 可排序(“s”)格式说明符
  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF"
  • “‘完整日期’‘T’‘小时’‘:’‘分钟’‘时间偏移’”

  • "yyyy'-'MM'-'dd'T'HH':'mmZ"
  • "yyyy'-'MM'-'dd'T'HH':'mm('+'/'-')HH':'mm"
  • ‘日期时间’

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFZ"
  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'-')HH':'mm"
  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF('+'/'-')HH':'mm"
  • 此粒度级别符合 RFC 3339 ,这是一种广泛使用的 ISO 8601 配置文件,用于交换日期和时间信息。 但是, System.Text.Json 实现存在一些限制。

  • RFC 3339 未指定秒的小数部分的最大位数,但指定如果存在秒的小数部分,则句点后面必须至少有一位数字。 System.Text.Json 中的实现允许最多 16 位数(以支持与其他编程语言和框架的互操作),但仅分析前 7 位数。 如果读取 DateTime DateTimeOffset 实例时秒的小数位数超过 16 位,则会引发 JsonException
  • RFC 3339 允许“T”和“Z”字符分别为“t”或“z”,但允许应用程序仅支持大写变体。 System.Text.Json 中的实现要求它们为“T”和“Z”。 如果读取 DateTime DateTimeOffset 实例时输入有效负载包含“t”或“z”,则会引发 JsonException
  • RFC 3339 指定日期和时间部分用“T”分隔,但允许应用程序用空格(“ ”)分隔它们。 System.Text.Json 要求日期和时间部分用“T”分隔。 如果读取 DateTime DateTimeOffset 实例时输入有效负载包含空格(“ ”),则会引发 JsonException
  • 如果秒有小数部分,则必须至少有一位数字。 不允许使用 2019-07-26T00:00:00. 。 尽管最多允许 16 个小数位数,但仅分析前 7 位数。 超出该范围的任何内容都将被视为零。 例如, 2019-07-26T00:00:00.1234567890 将按 2019-07-26T00:00:00.1234567 分析。 此方法是为了与 DateTime 实现保持兼容,该实现仅限于此解决方法。

    不支持跳跃秒。

    支持格式设置

    为格式设置定义了以下粒度级别:

  • “‘完整日期’‘T’‘部分时间’”

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss"( 可排序(“s”)格式说明符

    用于格式化不含秒小数部分且不含偏移信息的 DateTime

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF"

    用于格式化含秒小数部分但不含偏移信息的 DateTime

  • ‘日期时间’

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"

    用于格式化不含秒小数部分但含 UTC 偏移的 DateTime

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFZ"

    用于格式化含秒小数部分且含 UTC 偏移的 DateTime

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'-')HH':'mm"

    用于格式化不含秒小数部分但含本地偏移的 DateTime DateTimeOffset

  • "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF('+'/'-')HH':'mm"

    用于格式化含秒小数部分且含本地偏移的 DateTime DateTimeOffset

    此粒度级别符合 RFC 3339

    如果 DateTime DateTimeOffset 实例的 往返格式 表示形式的秒小数部分的末尾有零,则 JsonSerializer Utf8JsonWriter 将格式化该实例表示形式,而不在末尾使用零。 例如,其 往返格式 表示形式为 2019-04-24T14:50:17.1010000Z DateTime 实例将被 JsonSerializer Utf8JsonWriter 格式化为 2019-04-24T14:50:17.101Z

    如果 DateTime DateTimeOffset 实例的 往返格式 表示形式的秒小数部分全都为零,则 JsonSerializer Utf8JsonWriter 将格式化该实例表示形式,而不采用秒的小数部分。 例如,其 往返格式 表示形式为 2019-04-24T14:50:17.0000000+02:00 DateTime 实例将被 JsonSerializer Utf8JsonWriter 格式化为 2019-04-24T14:50:17+02:00

    截断秒小数位数中的零允许写入保留往返信息所需的最小输出。

    秒的小数部分最多写入七位数。 最大位数与 DateTime 实现一致,该实现仅限于此解决方法。

  •