Obsługa elementów DateTime i DateTimeOffset w pliku System.Text.Json
Biblioteka System.Text.Json
analizuje i zapisuje DateTime i DateTimeOffset wartości zgodnie z rozszerzonym profilem ISO 8601-1:2019.
Konwertery zapewniają niestandardową obsługę serializacji i deserializacji za pomocą polecenia JsonSerializer. Można również użyć polecenia Utf8JsonReader i Utf8JsonWriter zaimplementować obsługę niestandardową.
Obsługa formatu ISO 8601-1:2019
Typy JsonSerializer, Utf8JsonReader, Utf8JsonWriteri JsonElement analizują i zapisują DateTime i DateTimeOffset tekst zgodnie z rozszerzonym profilem formatu ISO 8601-1:2019. Na przykład 2019-07-26T16:59:57-05:00
.
DateTime i DateTimeOffset dane można serializować za pomocą polecenia 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 można DateTimeOffset również wykonać deserializacji za pomocą polecenia 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
W przypadku opcji domyślnych reprezentacje wejściowe DateTime i DateTimeOffset tekstowe muszą być zgodne z rozszerzonym profilem ISO 8601-1:2019. Próba deserializacji reprezentacji, które nie są zgodne z profilem, spowoduje JsonSerializer zgłoszenie błędu 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.
Obiekt JsonDocument zapewnia ustrukturyzowany dostęp do zawartości ładunku JSON, w tym DateTime DateTimeOffset i reprezentacji. W poniższym przykładzie pokazano, jak obliczyć średnią temperaturę w poniedziałek z kolekcji temperatur:
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
Próba obliczenia średniej temperatury na podstawie ładunku z niezgodnymi DateTime reprezentacjami spowoduje JsonDocument zgłoszenie błędu 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()
Dane i DateTimeOffset zapisy DateTime na niższym poziomieUtf8JsonWriter:
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 analizowanie DateTime i DateTimeOffset dane:
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
Próba odczytania niezgodnych formatów za Utf8JsonReader pomocą polecenia spowoduje zgłoszenie błędu 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()
Serializowanie właściwości DateOnly i TimeOnly
Program .NET 7+ System.Text.Json
obsługuje serializowanie i deserializacji DateOnly oraz TimeOnly typów. Rozważmy następujący obiekt:
sealed file record Appointment(
Guid Id,
string Description,
DateOnly Date,
TimeOnly StartTime,
TimeOnly EndTime);
Poniższy przykład serializuje Appointment
obiekt, wyświetla wynikowy kod JSON, a następnie deserializuje go z powrotem do nowego wystąpienia Appointment
typu. Na koniec oryginalne i nowo zdeserializowane wystąpienia są porównywane pod kątem równości, a wyniki są zapisywane w konsoli:
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}
""");
Powyższy kod:
- Obiekt
Appointment
jest tworzone i przypisywane do zmiennejappointment
. - Wystąpienie
appointment
jest serializowane do formatu JSON przy użyciu polecenia JsonSerializer.Serialize. - Wynikowy kod JSON jest zapisywany w konsoli programu .
- Kod JSON jest deserializowany z powrotem do nowego wystąpienia
Appointment
typu przy użyciu polecenia JsonSerializer.Deserialize. - Oryginalne i nowo zdeserializowane wystąpienia są porównywane pod kątem równości.
- Wynik porównania jest zapisywany w konsoli programu .
Obsługa niestandardowa dla i DateTimeDateTimeOffset
W przypadku korzystania z JsonSerializer
Jeśli chcesz, aby serializator wykonał niestandardowe analizowanie lub formatowanie, możesz zaimplementować niestandardowe konwertery. Oto kilka przykładów:
DateTime(Przesunięcie). Analizowanie i data/godzina(przesunięcie). ToString
Jeśli nie możesz określić formatów reprezentacji wejściowych DateTime lub DateTimeOffset tekstowych, możesz użyć DateTime(Offset).Parse
metody w logice odczytu konwertera.
Ta metoda umożliwia użycie metody . Rozbudowana obsługa platformy NET do analizowania różnych DateTime formatów i DateTimeOffset tekstu, w tym ciągów innych niż ISO 8601 i formatów ISO 8601, które nie są zgodne z rozszerzonym profilem ISO 8601-1:2019.
Takie podejście jest mniej wydajne niż użycie natywnej implementacji serializatora.
Do serializacji można użyć DateTime(Offset).ToString
metody w logice zapisu konwertera.
Ta metoda umożliwia zapisywanie DateTime i DateTimeOffset wartości przy użyciu dowolnego standardowego formatu daty i godziny oraz niestandardowych formatów daty i godziny.
Takie podejście jest również mniej wydajne niż użycie natywnej implementacji serializatora.
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"
Uwaga
Podczas implementowania JsonConverter<T>parametru , i T
ma DateTimewartość , typeToConvert
parametr zawsze będzie mieć wartość typeof(DateTime)
.
Parametr jest przydatny do obsługi przypadków polimorficznych i w przypadku używania typów ogólnych w celu uzyskania typeof(T)
wydajnego sposobu.
Utf8Parser i Utf8Formatter
Możesz użyć szybkich metod analizowania i formatowania opartych na protokole UTF-8 w logice konwertera, jeśli reprezentacje wejściowe DateTime lub DateTimeOffset tekstowe są zgodne z jednym z "R", "l", "O" lub "G" standardowych ciągów formatu daty i godziny albo chcesz napisać zgodnie z jednym z tych formatów. Takie podejście jest znacznie szybsze niż użycie i DateTime(Offset).Parse
DateTime(Offset).ToString
.
W poniższym przykładzie przedstawiono niestandardowy konwerter, który serializuje i deserializuje DateTime wartości zgodnie ze standardowym formatem "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"
Uwaga
Standardowy format "R" zawsze będzie mieć długość 29 znaków.
Format "l" (małe litery "L") nie jest udokumentowany z innymi standardowymi ciągami formatu daty i godziny, ponieważ jest obsługiwany tylko przez Utf8Parser
typy i Utf8Formatter
. Format to małe litery RFC 1123 (mała wersja formatu "R"). Na przykład "thu, 25 lip 2019 06:36:07 gmt".
Użyj wartości DateTime(Offset). Analizowanie jako rezerwowe
Jeśli zazwyczaj oczekujesz, że dane wejściowe DateTime lub DateTimeOffset dane będą zgodne z rozszerzonym profilem ISO 8601-1:2019, możesz użyć natywnej logiki analizowania serializatora. Można również zaimplementować mechanizm rezerwowy. W poniższym przykładzie pokazano, że po niepowodaniu analizowania DateTime reprezentacji tekstu przy użyciu metody konwerter pomyślnie analizuje dane przy TryGetDateTime(DateTime)użyciu polecenia 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"
Korzystanie z formatu daty epoki systemu Unix
Następujące konwertery obsługują format epoki Unix z przesunięciem strefy czasowej lub bez tego przesunięcia (wartości, takie jak /Date(1590863400000-0700)/
lub /Date(1590863400000)/
):
sealed class UnixEpochDateTimeOffsetConverter : 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, 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(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 = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
writer.WriteStringValue(formatted);
}
}
sealed class UnixEpochDateTimeConverter : 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, 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 = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime})/");
writer.WriteStringValue(formatted);
}
}
W przypadku korzystania z Utf8JsonWriter
Jeśli chcesz napisać reprezentację niestandardową DateTime lub DateTimeOffset tekstową za pomocą Utf8JsonWriterpolecenia , możesz sformatować niestandardową reprezentację w obiekcie String, ReadOnlySpan<Char>
ReadOnlySpan<Byte>
lub JsonEncodedText, a następnie przekazać ją do odpowiedniej Utf8JsonWriter.WriteStringValue metody lub Utf8JsonWriter.WriteString .
W poniższym przykładzie pokazano, jak można utworzyć format niestandardowy DateTime za pomocą ToString(String, IFormatProvider) metody , a następnie napisać za pomocą WriteStringValue(String) metody :
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
// }
W przypadku korzystania z Utf8JsonReader
Jeśli chcesz odczytać niestandardową DateTime lub DateTimeOffset tekstową reprezentację za Utf8JsonReaderpomocą polecenia , możesz uzyskać wartość bieżącego tokenu JSON jako metodę String using GetString() , a następnie przeanalizować wartość przy użyciu logiki niestandardowej.
W poniższym przykładzie pokazano, jak można pobrać niestandardową DateTimeOffset reprezentację tekstu przy użyciu metody , a następnie przeanalizować przy użyciu GetString() metody 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
Rozszerzony profil ISO 8601-1:2019 w pliku System.Text.Json
Składniki daty i godziny
Rozszerzony profil ISO 8601-1:2019 zaimplementowany w programie System.Text.Json definiuje następujące składniki dla reprezentacji daty i godziny. Te składniki służą do definiowania różnych obsługiwanych poziomów szczegółowości podczas analizowania i formatowania DateTime i DateTimeOffset reprezentacji.
Składnik | Format | opis |
---|---|---|
Year | „yyyy” | 0001-9999 |
Month | „MM” | 01-12 |
Dzień | „dd” | 01-28, 01-29, 01-30, 01-31 na podstawie miesiąca/roku. |
Godzina | „HH” | 00-23 |
Minuta | „mm” | 00-59 |
Second | „ss” | 00-59 |
Drugi ułamek | „FFFFFFF” | Co najmniej jedną cyfrę, maksymalnie 16 cyfr. |
Przesunięcie czasu | „K” | "Z" lub "('+'/'')HH':'mm". |
Czas częściowy | "HH':'mm':'ss[FFFFFFF]" | Czas bez informacji o przesunięcie UTC. |
Pełna data | "yyyy'-'MM'-'dd" | Data kalendarza. |
Pełny czas | "'Częściowy czas'K" | CZASU UTC dnia lub czasu lokalnego z przesunięciem czasu lokalnego między czasem lokalnym a UTC. |
Data i godzina | "'Full date'T'Full time'" | Data i godzina kalendarza dnia, na przykład 2019-07-26T16:59:57-05:00. |
Obsługa analizowania
Na potrzeby analizowania zdefiniowano następujące poziomy szczegółowości:
"Pełna data"
- "yyyy'-'MM'-'dd"
"'Full date'T'Hour':'Minute'"
- "yyyy'-'MM'-'dd'T'HH':'mm"
"'Full date'T'Partial time'"
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Specyfikator formatu Sortable ("s")
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss'". FFFFFFF"
"'Full date'T'Time hour'':'Minute''Time offset'"
- "yyyy'-'MM'-'dd'T'HH':'mmZ"
- "yyy'-'MM'-'dd'T'HH':'mm('+'/'-')HH':'mm"
"Data i godzina"
- "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"
Ten poziom szczegółowości jest zgodny z RFC 3339, powszechnie przyjęty profil ISO 8601 używany do wymiany informacji o dacie i godzinie. Jednak w implementacji
System.Text.Json
istnieje kilka ograniczeń.- RFC 3339 nie określa maksymalnej liczby cyfr ułamkowych sekund, ale określa, że co najmniej jedna cyfra musi podążać za kropką, jeśli istnieje sekcja ułamkowa sekunda. Implementacja w programie
System.Text.Json
umożliwia maksymalnie 16 cyfr (w celu obsługi międzyoperacyjności z innymi językami programowania i strukturami), ale analizuje tylko pierwsze siedem. Wartość JsonException zostanie wyrzucona, jeśli podczas odczytywaniaDateTime
iDateTimeOffset
wystąpień występuje więcej niż 16 cyfr ułamkowych sekund. - RFC 3339 umożliwia odpowiednio znaki "T" i "Z" jako "t" lub "z", ale umożliwia aplikacjom ograniczenie obsługi tylko wariantów wyższej litery. Implementacja w programie
System.Text.Json
wymaga, aby były to "T" i "Z". Element JsonException zostanie zgłoszony, jeśli ładunki wejściowe zawierają wartość "t" lub "z" podczas odczytywaniaDateTime
iDateTimeOffset
wystąpień. - RFC 3339 określa, że sekcje daty i godziny są oddzielone znakiem "T", ale umożliwia aplikacjom oddzielenie ich spacją ("") zamiast tego.
System.Text.Json
wymaga oddzielenia sekcji daty i godziny od "T". Element JsonException zostanie zgłoszony, jeśli ładunki wejściowe zawierają spację (" ") podczas odczytywaniaDateTime
iDateTimeOffset
wystąpień.
Jeśli liczba ułamków dziesiętnych występuje w sekundach, musi istnieć co najmniej jedna cyfra. 2019-07-26T00:00:00.
jest niedozwolona.
Chociaż dozwolone jest maksymalnie 16 cyfr ułamkowych, tylko pierwsze siedem jest analizowanych. Wszystko poza tym jest uważane za zero.
Na przykład zostanie przeanalizowany tak, 2019-07-26T00:00:00.1234567890
jakby był 2019-07-26T00:00:00.1234567
to .
Takie podejście utrzymuje zgodność z implementacją DateTime , która jest ograniczona do tej rozwiązania.
Sekundy przestępne nie są obsługiwane.
Obsługa formatowania
Do formatowania zdefiniowano następujące poziomy szczegółowości:
"'Full date'T'Partial time'"
"yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Specyfikator formatu Sortable ("s")
Służy do formatowania DateTime bez ułamkowych sekund i bez informacji przesunięcia.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'". FFFFFFF"
Służy do formatowania z DateTime ułamkowymi sekundami, ale bez informacji o przesunięciach.
"Data i godzina"
"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
Służy do formatowania bez DateTime sekund ułamkowych, ale z przesunięciem UTC.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'". FFFFFFFZ"
Służy do formatowania z DateTime sekundami ułamkowymi i przesunięciem UTC.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'')HH':'mm"
Służy do formatowania DateTime sekund ułamkowych lub DateTimeOffset bez, ale z przesunięciem lokalnym.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'". FFFFFFF('+'/'-')HH':'mm"
Służy do formatowania wartości DateTime lub DateTimeOffset z sekundami ułamkowymi i z przesunięciem lokalnym.
Ten poziom szczegółowości jest zgodny z RFC 3339.
Jeśli reprezentacja DateTime DateTimeOffset w formacie dwukierunkowym wystąpienia ma końcowe zera w sekundach ułamkowych, a następnie JsonSerializer Utf8JsonWriter sformatuje reprezentację wystąpienia bez zer końcowych.
Na przykład wystąpienie, którego reprezentacja DateTime formatu dwukierunkowego to 2019-04-24T14:50:17.1010000Z
, zostanie sformatowane jako 2019-04-24T14:50:17.101Z
i JsonSerializer Utf8JsonWriter.
Jeśli reprezentacja w formacie dwukierunkowym DateTime wystąpienia ma DateTimeOffset wszystkie zera w sekundach ułamkowych, a Utf8JsonWriter następnie JsonSerializer sformatuje reprezentację wystąpienia bez sekund ułamkowych.
Na przykład wystąpienie, którego reprezentacja DateTime formatu dwukierunkowego to 2019-04-24T14:50:17.0000000+02:00
, zostanie sformatowane jako 2019-04-24T14:50:17+02:00
i JsonSerializer Utf8JsonWriter.
Obcięcie zer w cyfrach ułamkowych i sekund pozwala na najmniejsze dane wyjściowe potrzebne do zachowania informacji w obie strony do zapisania.
Zapisywana jest maksymalna liczba cyfr z siedmiu ułamkowych sekund. Ta maksymalna wartość jest zgodna z implementacją DateTime , która jest ograniczona do tej rozdzielczości.