Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
A biblioteca System.Text.Json analisa e grava os valores DateTime e DateTimeOffset de acordo com o perfil estendido ISO 8601-1:2019.
Os conversores fornecem suporte personalizado para serialização e desserialização com JsonSerializer. Também é possível usar Utf8JsonReader e Utf8JsonWriter para implementar o suporte personalizado.
Suporte para o formato ISO 8601-1:2019
Os tipos JsonSerializer, Utf8JsonReader, Utf8JsonWriter e JsonElement analisam e gravam representações de texto DateTime e DateTimeOffset de acordo com o perfil estendido do formato ISO 8601-1:2019, por exemplo, 2019-07-26T16:59:57-05:00.
Os dados DateTime e DateTimeOffset podem ser serializados com 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 e DateTimeOffset também podem ser desserializados com 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
Com as opções padrão, as representações de texto de entrada DateTime e DateTimeOffset devem estar em conformidade com o perfil estendido ISO 8601-1:2019. Se você tentar desserializar representações que não estão em conformidade com o perfil, JsonSerializer gerará um 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 fornece acesso estruturado ao conteúdo de uma carga JSON, incluindo DateTime e DateTimeOffset representações. O exemplo a seguir mostra como calcular a temperatura média às segundas-feiras a partir de uma coleção de temperaturas:
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
Se você tentar calcular a temperatura média dada uma carga com representações não compatíveis DateTime , JsonDocument gerará um 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()
O nível inferior Utf8JsonWriter grava dados DateTime e 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 analisa dados DateTime e 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
Se você tentar ler formatos não compatíveis com Utf8JsonReader, ele gerará um 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()
Serializar as propriedades DateOnly e TimeOnly
Com o .NET 7+, o System.Text.Json dá suporte à serialização e desserialização dos tipos DateOnly e TimeOnly. Considere o seguinte objeto:
sealed file record Appointment(
Guid Id,
string Description,
DateOnly Date,
TimeOnly StartTime,
TimeOnly EndTime);
O exemplo a seguir serializa um objeto Appointment, exibe o JSON resultante e, em seguida, desserializa-o novamente em uma nova instância do tipo Appointment. Por fim, as instâncias originais e recém-desserializadas são comparadas quanto à igualdade e os resultados são gravados no console:
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}
""");
No código anterior:
- Um objeto
Appointmenté instanciado e atribuído à variávelappointment. - A instância
appointmenté serializada para JSON usando JsonSerializer.Serialize. - O JSON resultante é gravado no console.
- O JSON é desserializado novamente em uma nova instância do tipo
Appointmentusando JsonSerializer.Deserialize. - As instâncias originais e recém-desserializadas são comparadas quanto à igualdade.
- O resultado da comparação é gravado no console.
Suporte personalizado para DateTime e DateTimeOffset
Ao usar JsonSerializer
Para que o serializador execute a análise ou a formatação personalizadas, você poderá implementar conversores personalizados. As seções a seguir mostram alguns exemplos:
- DateTime(Offset). Análise e DateTime(Offset). ToString
- Utf8Parser e Utf8Formatter
- Use DateTime(Offset). Parse como uma alternativa
- Usar o formato de data de época do Unix
DateTime(Offset).Parse e DateTime(Offset).ToString
Se você não conseguir determinar os formatos de suas representações de entrada de texto DateTime ou DateTimeOffset, poderá usar o método DateTime(Offset).Parse na lógica de leitura do conversor.
Esse método permite que você use o suporte amplo do .NET para analisar vários formatos de texto DateTime e DateTimeOffset, incluindo cadeias de caracteres fora dos formatos ISO 8601 e ISO 8601 que não estão em conformidade com o perfil ISO 8601-1:2019 estendido.
Essa abordagem tem um desempenho menor do que o uso da implementação nativa do serializador.
Para serializar, você pode usar o método DateTime(Offset).ToString na lógica de gravação do conversor.
Esse método permite gravar os valores DateTime e DateTimeOffset usando quaisquer formatos de data e hora padrão e os formatos de data e hora personalizados.
Essa abordagem também tem um desempenho significativamente menor do que o uso da implementação nativa do serializador.
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"
Observação
Ao implementar JsonConverter<T>, e T é DateTime, o parâmetro typeToConvert sempre será typeof(DateTime).
O parâmetro é útil para lidar com casos polimórficos e ao usar genéricos para obter typeof(T) com alto desempenho.
Utf8Parser e Utf8Formatter
Você pode usar métodos rápidos de análise e formatação baseados em UTF 8 em sua lógica de conversor se suas representações de entrada de texto DateTime ou DateTimeOffset estiverem em conformidade com uma das cadeias de caracteres padrão de formato de data e hora "R", "l", "O" ou "G" ou se desejar gravar de acordo com um desses formatos. Essa abordagem é muito mais rápida do que ao usar DateTime(Offset).Parse e DateTime(Offset).ToString.
O exemplo a seguir mostra um conversor personalizado que serializa e desserializa os valores DateTime de acordo com o formato padrão "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"
Observação
O formato padrão "R" sempre terá 29 caracteres.
O formato "l" ("L" minúsculo) não está documentado com as outras cadeias de caracteres de formato de data e hora padrão porque tem suporte apenas pelos tipos Utf8Parser e Utf8Formatter. O formato é RFC 1123 em minúsculas (uma versão em minúsculas do formato “R”). Por exemplo, "thu, 25 jul 2019 06:36:07 gmt".
Use DateTime(Offset).Parse como um fallback
Se você geralmente espera que sua entrada de dadosDateTime ou DateTimeOffset esteja em conformidade com o perfil estendido ISO 8601-1:2019, você poderá usar a lógica de análise nativa do serializador. Você também pode implementar um mecanismo de fallback. O exemplo a seguir mostra que, depois de não analisar uma representação de texto DateTime usando TryGetDateTime(DateTime), o conversor analisa com êxito os dados usando 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"
Usar o formato de data de época do Unix
Os conversores a seguir manipulam o formato de época Unix com ou sem um deslocamento de fuso horário (valores como /Date(1590863400000-0700)/ ou /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);
}
}
Ao usar Utf8JsonWriter
Se você quiser gravar uma representação de texto personalizada DateTime ou DateTimeOffset com Utf8JsonWriter, você poderá formatar sua representação personalizada para String, ReadOnlySpan<Byte>, ReadOnlySpan<Char> ou JsonEncodedText e, em seguida, passá-la para o método Utf8JsonWriter.WriteStringValue ou Utf8JsonWriter.WriteString correspondente.
O exemplo a seguir mostra como um formato personalizado DateTime pode ser criado com ToString(String, IFormatProvider) e, em seguida, gravado com o método 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
// }
Ao usar Utf8JsonReader
Se você quiser ler uma representação personalizada DateTime ou DateTimeOffset de texto com Utf8JsonReader, poderá obter o valor do token JSON atual como um String usando o método GetString() e, em seguida, processar o valor usando a lógica personalizada.
O exemplo a seguir mostra como uma representação de texto personalizada DateTimeOffset pode ser recuperada usando o método GetString() e, em seguida, analisada usando 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
O perfil ISO 8601-1:2019 estendido em System.Text.Json
Componentes de data e hora
O perfil ISO 8601-1:2019 estendido implementado em System.Text.Json define os seguintes componentes para representações de data e hora. Esses componentes são usados para definir vários níveis de granularidade com suporte ao analisar e formatar as representações DateTime e DateTimeOffset.
| Componente | Formatar | Descrição |
|---|---|---|
| Ano | "yyyyy" | 0001-9999 |
| Mês | "MM" | 01-12 |
| Dia | "dd" | 01-28, 01-29, 01-30, 01-31 com base no mês/ano. |
| Hora | "HH" | 00-23 |
| Minuto | "mm" | 00-59 |
| Segundo | "ss" | 00-59 |
| Segunda fração | "FFFFFFF" | Mínimo de um dígito, máximo de 16 dígitos. |
| Deslocamento de horário | "K" | "Z" ou "('+'/'-')HH':'mm". |
| Tempo parcial | "HH':'mm':'ss[FFFFFFF]" | Tempo sem informações de diferença UTC. |
| Data completa | "yyyyy'-'MM'-'dd" | Data do calendário. |
| Tempo completo | 'Tempo parcial'K | UTC do dia ou hora local do dia com a diferença de tempo entre a hora local e UTC. |
| Data e hora | "'Data completa''T''Tempo integral'" | Data e hora do calendário, por exemplo, 2019-07-26T16:59:57-05:00. |
Suporte para análise
Os seguintes níveis de granularidade são definidos para análise:
'Data completa'
- "yyyyy'-'MM'-'dd"
"'Data completa'''T''Hora':'Minuto'"
- "yyyyy'-'MM'-'dd'T'HH':'mm"
"'Data completa''T''Tempo parcial'"
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Especificador de formato ("s") classificável)
- "yyyyy'-'MM'-'dd'T'HH':'mm':'ss'." FFFFFFF"
"'Data completa'''T''Hora'':'Minuto'''Deslocamento de tempo'"
- "yyyyy'-'MM'-'dd'T'HH':'mmZ"
- "yyyyy'-'MM'-'dd'T'HH':'mm('+'/'-')HH':'mm"
'Data e hora'
- "yyyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
- "yyyyy'-'MM'-'dd'T'HH':'mm':'ss'." FFFFFFFZ"
- "yyyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'-')HH':'mm"
- "yyyyy'-'MM'-'dd'T'HH':'mm':'ss'." FFFFFFF('+'/'-')HH':'mm"
Esse nível de granularidade está em conformidade com o RFC 3339, um perfil amplamente adotado do ISO 8601 usado para trocar informações de data e hora. No entanto, há algumas restrições na implementação de
System.Text.Json.- O RFC 3339 não especifica um número máximo de dígitos de segundo fracionário, mas especifica que pelo menos um dígito deve seguir o período, se uma seção fracionária de segundo estiver presente. A implementação em
System.Text.Jsonpermite até 16 dígitos (para dar suporte à interoperabilidade com outras estruturas e linguagens de programação), mas analisa apenas os sete primeiros. JsonException será gerado se houver mais de 16 segundos dígitos fracionários ao gravar instânciasDateTimeeDateTimeOffset. - O RFC 3339 permite que os caracteres "T" e "Z" sejam "t" ou "z", respectivamente, mas permite que os aplicativos limitem o suporte apenas às variantes em maiúsculas. A implementação em
System.Text.Jsonexige que eles sejam "T" e "Z". JsonException será gerado se as cargas de entrada contiverem "t" ou "z" ao ler as instânciasDateTimeeDateTimeOffset. - O RFC 3339 especifica que as seções de data e hora são separadas por "T", mas permite que os aplicativos os separem por um espaço (" ").
System.Text.Jsonrequer que as seções de data e hora sejam separadas por "T". JsonException será gerado se as cargas de entrada contiverem um espaço (" ") ao ler as instânciasDateTimeeDateTimeOffset.
Se houver frações decimais por segundos, deve haver pelo menos um dígito.
2019-07-26T00:00:00. não é permitido.
Enquanto até 16 dígitos fracionários são permitidos, apenas os sete primeiros são analisados. Qualquer coisa além disso é considerada zero.
Por exemplo, 2019-07-26T00:00:00.1234567890 será analisado como se fosse 2019-07-26T00:00:00.1234567.
Essa abordagem se mantém compatível com a implementação de DateTime, que é limitada a essa resolução.
Não há suporte para segundos bissextos.
Suporte para formatação
Os seguintes níveis de granularidade são definidos para formatação:
"'Data completa''T''Tempo parcial'"
"yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Especificador de formato ("s") classificável)
Usado para formatar DateTime sem segundos fracionários e sem informações de diferença.
"yyyyy'-'MM'-'dd'T'HH':'mm':'ss'." FFFFFFF"
Usado para formatar DateTime com segundos fracionários, mas sem informações de diferença.
'Data e hora'
"yyyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
Usado para formatar DateTime sem segundos fracionários, mas com uma diferença UTC.
"yyyyy'-'MM'-'dd'T'HH':'mm':'ss'." FFFFFFFZ"
Usado para formatar DateTime com segundos fracionários e com uma diferença UTC.
"yyyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'-')HH':'mm"
Usado para formatar DateTime ou DateTimeOffset sem segundos fracionários, mas com uma diferença local.
"yyyyy'-'MM'-'dd'T'HH':'mm':'ss'." FFFFFFF('+'/'-')HH':'mm"
Usado para formatar DateTime ou DateTimeOffset com segundos fracionários e com uma diferença local.
Esse nível de granularidade está em conformidade com o RFC 3339.
Se a representação de formato de ida e volta de uma instância DateTime ou DateTimeOffset tiver zeros à direita em seus segundos fracionários, JsonSerializer e Utf8JsonWriter formatará uma representação da instância sem zeros à direita.
Por exemplo, uma instância DateTime cuja representação de formato de ida e volta é 2019-04-24T14:50:17.1010000Z, será formatada como 2019-04-24T14:50:17.101Z por JsonSerializer e Utf8JsonWriter.
Se a representação de formato de ida e volta de uma instância DateTime ou DateTimeOffset tiver todos os zeros em seus segundos fracionários, JsonSerializer e Utf8JsonWriter formatará uma representação da instância sem segundos fracionários.
Por exemplo, uma instância DateTime cuja representação de formato de ida e volta é 2019-04-24T14:50:17.0000000+02:00, será formatada como 2019-04-24T14:50:17+02:00 por JsonSerializer e Utf8JsonWriter.
Truncar zeros em dígitos de segundos fracionários permite que a menor saída necessária para preservar as informações em uma viagem de ida e volta seja gravada.
Um máximo de sete dígitos fracionários são gravados. Esse valor máximo se alinha à implementação DateTime, que é limitada a essa resolução.