Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Библиотека System.Text.Json анализирует и записывает DateTime и DateTimeOffset значения в соответствии с расширенным профилем ISO 8601-1:2019.
Преобразователи обеспечивают настраиваемую поддержку сериализации и десериализации с помощью JsonSerializer. Вы также можете использовать Utf8JsonReader и Utf8JsonWriter, чтобы реализовать пользовательскую поддержку.
Поддержка формата ISO 8601-1:2019
JsonSerializer, Utf8JsonReader, Utf8JsonWriter и JsonElement типы парсинга и записи текстовых представлений DateTime и DateTimeOffset в соответствии с расширенным профилем формата ISO 8601-1:2019, например, 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""}";
try
{
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. - Экземпляр
appointmentсериализуется в JSON с помощью JsonSerializer.Serialize. - Результирующий json записывается в консоль.
- JSON десериализирован обратно в новый экземпляр
Appointmentтипа с помощью JsonSerializer.Deserialize. - Исходные и недавно десериализированные экземпляры сравниваются на идентичность.
- Результат сравнения записывается в консоль.
Настраиваемая поддержка для DateTime и DateTimeOffset
При использовании JsonSerializer
Если вы хотите, чтобы сериализатор выполнял пользовательский анализ или форматирование, можно реализовать пользовательские преобразователи. В следующих разделах показаны несколько примеров:
- DateTime(Offset).Parse и DateTime(Offset).ToString
- Utf8Parser и Utf8Formatter
- Используйте DateTime(Offset).Parse как резервный вариант
- Используйте формат даты эпохи Unix
DateTime(Offset). Синтаксический анализ и DateTime(Offset). ToString
Если вы не можете определить форматы входных DateTime или DateTimeOffset текстовых представлений, можно использовать DateTime(Offset).Parse метод в логике чтения преобразователя.
Этот метод позволяет вам использовать обширную поддержку .NET для анализа различных текстовых форматов DateTime и DateTimeOffset, включая строки, не соответствующие ISO 8601, и форматы ISO 8601, которые не соответствуют расширенному стандарту ISO 8601-1:2019.
Этот подход менее производителен, чем использование родной реализации сериализатора.
Для сериализации в логике записи преобразователя можно использовать метод 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.
try
{
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.
В логике преобразователя можно использовать быстрые методы синтаксического анализа и форматирования на основе UTF-8, если входные DateTime или текстовые представления соответствуют одной из строк стандартного формата даты и DateTimeOffset времени типа "R", "L", "O" или "G" или вы хотите написать в соответствии с одним из этих форматов. Этот подход гораздо быстрее, чем использование DateTime(Offset).Parse и DateTime(Offset).ToString.
В следующем примере показан настраиваемый преобразователь, который сериализует и десериализирует DateTime значения в соответствии со стандартным форматом R:
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.
try
{
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, вы можете использовать собственную логику синтаксического анализа сериализатора. Вы также можете реализовать резервный механизм. В следующем примере показано, что после сбоя синтаксического анализа текстового представления DateTime с помощью TryGetDateTime(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.
try
{
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
Следующие преобразователи обрабатывают формат эпохи Unix со смещением часового пояса или без него (например /Date(1590863400000-0700)/ или /Date(1590863400000)/):
sealed class UnixEpochDateTimeOffsetConverter : System.Text.Json.Serialization.JsonConverter<DateTimeOffset>
{
static readonly DateTimeOffset s_epoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
static readonly Regex s_regex = new(
"^/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);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
|| !int.TryParse(match.Groups[3].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
|| !int.TryParse(match.Groups[4].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
{
throw new System.Text.Json.JsonException();
}
int sign = match.Groups[2].Value[0] == '+' ? 1 : -1;
TimeSpan utcOffset = new(hours * sign, minutes * sign, 0);
return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset);
}
public override void Write(
Utf8JsonWriter writer,
DateTimeOffset value,
JsonSerializerOptions options)
{
long unixTime = value.ToUnixTimeMilliseconds();
TimeSpan utcOffset = value.Offset;
string formatted = string.Create(
CultureInfo.InvariantCulture,
$"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
writer.WriteStringValue(formatted);
}
}
sealed class UnixEpochDateTimeConverter : System.Text.Json.Serialization.JsonConverter<DateTime>
{
static readonly DateTime s_epoch = new(1970, 1, 1, 0, 0, 0);
static readonly Regex s_regex = new(
"^/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);
if (
!match.Success
|| !long.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime))
{
throw new System.Text.Json.JsonException();
}
return s_epoch.AddMilliseconds(unixTime);
}
public override void Write(
Utf8JsonWriter writer,
DateTime value,
JsonSerializerOptions options)
{
long unixTime = (value - s_epoch).Ticks / TimeSpan.TicksPerMillisecond;
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime})/");
writer.WriteStringValue(formatted);
}
}
При использовании Utf8JsonWriter
Если вы хотите написать пользовательское DateTime или DateTimeOffset текстовое представление с Utf8JsonWriter, вы можете отформатировать своё пользовательское представление в String, ReadOnlySpan<Byte>, ReadOnlySpan<Char> или JsonEncodedText, а затем передать его соответствующему методу Utf8JsonWriter.WriteStringValue или Utf8JsonWriter.WriteString.
В следующем примере показано, как можно создать настраиваемый DateTime формат с использованием ToString(String, IFormatProvider), а затем записать его с помощью метода 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
Если вы хотите прочитать пользовательское DateTime или DateTimeOffset текстовое представление с Utf8JsonReader, вы можете получить значение текущего токена JSON в виде String с использованием метода GetString(), а затем проанализировать это значение с помощью пользовательской логики.
В следующем примере показано, как можно получить пользовательское DateTimeOffset текстовое представление с помощью метода GetString(), а затем проанализировать с помощью 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
Расширенный профиль ISO 8601-1:2019 в System.Text.Json
Компоненты даты и времени
Расширенный профиль ISO 8601-1:2019, реализованный в System.Text.Json, определяет следующие компоненты для представлений даты и времени. Эти компоненты используются для определения различных поддерживаемых уровней детализации при анализе и форматировании DateTime и DateTimeOffset представлениях.
| Компонент | Формат | Описание |
|---|---|---|
| Год | гггг | 0001-9999 |
| месяц | "MM" | 01.12 |
| день | "dd" | 01-28, 01-29, 01-30, 01-31 на основе месяца или года. |
| Час | "HH" | 00-23 |
| Минута | "mm" | 00-59 |
| Второй | "сс" | 00-59 |
| Вторая дробь | FFFFFFF | Не менее одной цифры, не более 16 цифр. |
| Смещение времени | "K" | Либо Z, либо "('+'/'-)HH':'mm". |
| Частичное время | "HH':'mm':'ss[FFFFFFF]" | Время без информации о смещении UTC. |
| Полная дата | "гггг'-'ММ'-дд" | Календарная дата. |
| Полный рабочий день | «Частичное время» K | Время по UTC или местное время с указанием смещения между местным временем и временем по UTC. |
| Дата и время | "'Полная дата'T'Полный рабочий день'" | Дата и время дня календаря, например 2019-07-26T16:59:57-05:00. |
Поддержка синтаксического анализа
Для синтаксического анализа определены следующие уровни детализации:
"Полная дата"
- "гггг'-'ММ'-дд"
"'Полная дата'T'Часы':'Минуты'"
- "гггг'-'ММ'-дд'T'HH':'mm"
"'Полная дата''T''Частичное время'"
- "гггг'-'MM'-'dd'T'HH':'mm':'ss" (Спецификатор формата сортировки ("s"))
- "гггг'-'ММ'-'дд'T'HH':'mm':'ss'.'FFFFFFF"
"'Full date'T'Time hour':'Minute'Minute''Time offset'" (Смещение времени)
- "гггг'-'ММ'-dd'T'HH':'mmZ"
- гггг'-'ММ'-'dd'T'HH':'mm('+'/'-')HH':'mm
"Дата и время"
- "гггг'-'ММ'-dd'T'HH':'mm'ssZ"
- "гггг'-'ММ'-'dd'T'HH':'mm':'ss'.'FFFFFFFZ"
- "гггг'-'ММ'-dd'T'HH':'mm'ss('+'/'-)HH':'mm"
- гггг'-'ММ'-'dd'T'HH':'mm':'ss'.'FFFFFFF('+'/'-')HH':'mm
Этот уровень детализации соответствует стандарту RFC 3339, широко принятому профилю ISO 8601, используемому для чередующихся сведений о дате и времени. Однако в реализации
System.Text.Jsonсуществует несколько ограничений.- RFC 3339 не указывает максимальное количество дробных секундных цифр, но указывает, что по крайней мере одна цифра должна следовать за периодом, если присутствует раздел дробной секунды.
System.Text.JsonРеализация позволяет использовать до 16 символов (для поддержки взаимодействия с другими языками программирования и фреймворками), но разбирает только первые семь. При попытке прочитать экземпляры JsonException иDateTime, будет выброшено исключение, если имеется более 16 цифр дробной части секунды. - RFC 3339 позволяет символам T и Z быть "t" или "z" соответственно, но позволяет приложениям ограничить поддержку только вариантов верхнего регистра. Реализация в
System.Text.Jsonдолжна требовать "T" и "Z". При чтении JsonException иDateTimeDateTimeOffsetбудет выбрасываться исключение, если входные полезные данные содержат "t" или "z". - RFC 3339 указывает, что разделы даты и времени разделяются "T", но позволяют приложениям разделять их пробелами ("") вместо этого.
System.Text.JsonТребуется разделение разделов даты и времени с помощью "T". Если входные данные содержат пробел (" ") при чтении экземпляров JsonException иDateTime, будет выброшено исключение.
Если в секундах имеется десятичная дробь, должна быть как минимум одна цифра.
2019-07-26T00:00:00. запрещено.
Хотя допускается до 16 дробных цифр, только первые семь анализируются. Все, что выходит за рамки этого, считается нулевым.
Например, 2019-07-26T00:00:00.1234567890 будет проанализирован так, как будто это 2019-07-26T00:00:00.1234567.
Этот подход поддерживает совместимость с DateTime реализацией, которая ограничена этим разрешением.
Секунды прыжка не поддерживаются.
Поддержка форматирования
Для форматирования определены следующие уровни детализации:
"'Полная дата''T''Частичное время'"
"гггг'-'MM'-'dd'T'HH':'mm':'ss" (Спецификатор формата сортировки ("s"))
Используется для форматирования DateTime без дробных секунд и без сведений смещения.
"гггг'-'ММ'-'дд'T'HH':'mm':'ss'.'FFFFFFF"
Используется для форматирования DateTime с дробными секундами, но без информации о смещении.
"Дата и время"
"гггг'-'ММ'-dd'T'HH':'mm'ssZ"
Используется для форматирования DateTime без дробных секунд, но со смещением UTC.
"гггг'-'ММ'-'dd'T'HH':'mm':'ss'.'FFFFFFFZ"
Используется для форматирования DateTime с дробными секундами и смещением по UTC.
"гггг'-'ММ'-dd'T'HH':'mm'ss('+'/'-)HH':'mm"
Используется для форматирования DateTime или DateTimeOffset без дробных секунд, но с локальным смещением.
гггг'-'ММ'-'dd'T'HH':'mm':'ss'.'FFFFFFF('+'/'-')HH':'mm
Используется для форматирования DateTime или DateTimeOffset с дробными секундами и локальным смещением.
Этот уровень детализации соответствует RFC 3339.
Если представление обратимого формата для экземпляра DateTimeDateTimeOffset имеет нули в конце дробных долей секунд, то JsonSerializer и Utf8JsonWriter отформатируют представление экземпляра без конечных нулей.
Например, экземпляр, представление которого в формате кругового преобразования эквивалентно DateTime, будет отформатировано как с помощью 2019-04-24T14:50:17.1010000Z и 2019-04-24T14:50:17.101Z.
Если представление формата кругового пути экземпляра DateTimeDateTimeOffset имеет все нули в дробных секундах, то JsonSerializer и Utf8JsonWriter отформатирует представление экземпляра без дробных секунд.
Например, экземпляр, представление которого в формате кругового преобразования эквивалентно DateTime, будет отформатировано как с помощью 2019-04-24T14:50:17.0000000+02:00 и 2019-04-24T14:50:17+02:00.
Усечение нулей в дробных долях секунды позволяет записать минимальный объем выходных данных, необходимый для сохранения информации при круговом преобразовании.
Записывается не более семи цифр дробной части секунд. Это максимальное DateTime значение соответствует реализации, которая ограничена этим разрешением.