Podpora DateTime a DateTimeOffset v System.Text.Json

Knihovna System.Text.Json analyzuje a zapisuje DateTime a DateTimeOffset hodnoty podle rozšířeného profilu ISO 8601-1:2019. Převaděče poskytují vlastní podporu pro serializaci a deserializaci pomocí JsonSerializer. Můžete také použít Utf8JsonReader a Utf8JsonWriter implementovat vlastní podporu.

Podpora formátu ISO 8601-1:2019

JsonSerializer, Utf8JsonReader, Utf8JsonWritera JsonElement typy parsovat a zapisovat DateTime a DateTimeOffset text reprezentace podle rozšířeného profilu formátu ISO 8601-1:2019. Například 2019-07-26T16:59:57-05:00.

DateTime a DateTimeOffset data lze serializovat pomocí 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 a DateTimeOffset lze také deserializovat pomocí 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

U výchozích možností musí vstupní DateTime a DateTimeOffset textové reprezentace odpovídat rozšířenému profilu ISO 8601-1:2019. Pokus o deserializaci reprezentací, které neodpovídají profilu, způsobí JsonSerializer vyvolání 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.

Poskytuje JsonDocument strukturovaný přístup k obsahu datové části JSON včetně DateTime a DateTimeOffset reprezentací. Následující příklad ukazuje, jak vypočítat průměrnou teplotu v pondělí z kolekce teplot:

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

Pokus o výpočet průměrné teploty zadanou datovou částí s nekompatibilními DateTime reprezentacemi způsobí JsonDocument vyvolání 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()

Nižší úroveň Utf8JsonWriter zapisuje DateTime a DateTimeOffset data:

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 parsuje DateTime a DateTimeOffset data:

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

Pokus o čtení nekompatibilníchformátůch 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()

Serializace vlastností DateOnly a TimeOnly

S .NET 7+ System.Text.Json podporuje serializaci a deserializaci DateOnly a TimeOnly typy. Představte si následující objekt:

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

Následující příklad serializuje Appointment objekt, zobrazí výsledný JSON a pak deserializuje zpět do nové instance Appointment typu. Nakonec se původní a nově deserializované instance porovnávají s rovností a výsledky se zapisují do konzoly:

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}
    """);

V předchozím kódu:

  • Vytvoří Appointment instanci objektu appointment a přiřadí se k proměnné.
  • Instance je serializována appointment do FORMÁTU JSON pomocí JsonSerializer.Serialize.
  • Výsledný json se zapíše do konzoly.
  • JSON se deserializuje zpět do nové instance Appointment typu pomocí JsonSerializer.Deserialize.
  • Původní a nově deserializované instance se porovnávají s rovností.
  • Výsledek porovnání se zapíše do konzoly.

Vlastní podpora pro DateTime a DateTimeOffset

Při použití JsonSerializer

Pokud chcete, aby serializátor prováděl vlastní analýzu nebo formátování, můžete implementovat vlastní převaděče. Tady je pár příkladů:

DateTime(Offset). Parsování a DateTime(Posun) ToString

Pokud nemůžete určit formáty vstupních DateTime nebo DateTimeOffset textových reprezentací, můžete použít metodu DateTime(Offset).Parse v logice čtení převaděče. Tato metoda umožňuje použít . Rozsáhlá podpora analýzy různých DateTime a DateTimeOffset textových formátů, včetně řetězců jiných než ISO 8601 a formátů ISO 8601, které nevyhovují rozšířenému profilu ISO 8601-1:2019. Tento přístup je méně výkonný než použití nativní implementace serializátoru.

Pro serializaci můžete použít metodu v logice zápisu DateTime(Offset).ToString převaděče. Tato metoda umožňuje psát DateTime a hodnoty pomocí libovolného standardního formátu data a DateTimeOffset času a vlastních formátů data a času. Tento přístup je také méně výkonný než použití nativní implementace serializátoru.

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"

Poznámka:

Při implementaci JsonConverter<T>a T je DateTime, typeToConvert parametr bude vždy typeof(DateTime). Tento parametr je užitečný pro zpracování polymorfních případů a při použití obecných typů k typeof(T) získání výkonnějšího způsobu.

Utf8Parser a Utf8Formatter

V logice převaděče můžete použít rychlé metody analýzy a formátování založené na kódování UTF-8, pokud jsou vstupní DateTime nebo DateTimeOffset textové reprezentace kompatibilní s jedním z řetězců standardního formátu data a času založených na kódování R, L nebo G nebo podle jednoho z těchto formátů. Tento přístup je mnohem rychlejší než použití DateTime(Offset).Parse a DateTime(Offset).ToString.

Následující příklad ukazuje vlastní převaděč, který serializuje a deserializuje DateTime hodnoty podle standardního formátu "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://video2.skills-academy.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"

Poznámka:

Standardní formát "R" bude vždy dlouhý 29 znaků.

Formát "l" (malými písmeny "L") není zdokumentovaný s jinými standardními řetězci formátu data a času, protože je podporovaný pouze typy Utf8Parser a Utf8Formatter typy. Formát je malými písmeny RFC 1123 (malá písmena ve formátu R). Například "thu, 25 jul 2019 06:36:07 gmt".

Použijte dateTime(posun). Parsovat jako záložní

Pokud obecně očekáváte, že vaše vstupy DateTime nebo DateTimeOffset data odpovídají rozšířenému profilu ISO 8601-1:2019, můžete použít nativní logiku analýzy serializátoru. Můžete také implementovat záložní mechanismus. Následující příklad ukazuje, že po selhání parsování textové reprezentace DateTime pomocí TryGetDateTime(DateTime)převaděč úspěšně parsuje data pomocí 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"

Použití formátu kalendářního data unixové epochy

Následující převaděče zpracovávají formát unixové epochy s posunem časového pásma (hodnoty jako /Date(1590863400000-0700)/ /Date(1590863400000)/nebo):

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);
    }
}

Při použití Utf8JsonWriter

Pokud chcete napsat vlastní DateTime nebo DateTimeOffset textovou reprezentaci pomocí Utf8JsonWriter, můžete vlastní reprezentaci naformátovat na String, ReadOnlySpan<Byte>ReadOnlySpan<Char>nebo JsonEncodedText, a pak ji předat odpovídající Utf8JsonWriter.WriteStringValue nebo Utf8JsonWriter.WriteString metodě.

Následující příklad ukazuje, jak lze vytvořit vlastní DateTime formát s ToString(String, IFormatProvider) metodou a pak ji WriteStringValue(String) zapsat:

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
// }

Při použití Utf8JsonReader

Pokud chcete přečíst vlastní DateTime nebo DateTimeOffset textovou reprezentaci pomocí Utf8JsonReader, můžete získat hodnotu aktuálního tokenu JSON jako metodu String pomocí GetString() metody a pak parsovat hodnotu pomocí vlastní logiky.

Následující příklad ukazuje, jak lze pomocí metody načíst GetString() vlastní DateTimeOffset textovou reprezentaci a pak analyzovat pomocí 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

Rozšířený profil ISO 8601-1:2019 v system.Text.Json

Komponenty data a času

Rozšířený profil ISO 8601-1:2019 implementovaný v System.Text.Json definici následujících součástí pro vyjádření data a času. Tyto komponenty se používají k definování různých podporovaných úrovní členitosti při analýze a formátování DateTime a DateTimeOffset reprezentaci.

Komponenta Formát Popis
Year "yyyy" 0001-9999
Month "MM" 01-12
Den "dd" 01-28, 01-29, 01-30, 01-31 na základě měsíce/roku.
Hodina "HH" 00-23
Minuta "mm" 00-59
Second "ss" 00-59
Druhý zlomek "FFFFFFF" Minimálně jedna číslice, maximálně 16 číslic.
Časový posun "K" Buď "Z" nebo "('+'/'-')HH':'mm".
Částečný čas "HH':'mm':'ss[FFFFFFF]" Čas bez informací o posunu UTC
Úplné datum "yyyy'-'MM'-'dd" Datum kalendáře.
Plný úvazek "'Částečný čas'K" UTC dne nebo místního dne s časovým posunem mezi místním časem a UTC.
Datum a čas "Úplné datum''T'Full time'' Datum a čas kalendáře, například 2019-07-26T16:59:57-05:00.

Podpora analýzy

Pro parsování jsou definovány následující úrovně členitosti:

  1. Úplné datum

    1. "yyyy'-'MM'-'dd"
  2. "'Celé datum''T'Hour'':'Minute'"

    1. "yyyy'-'MM'-'dd'T'HH':'mm"
  3. "Úplné datum''T'Částečný čas'"

    1. "yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Specifikátor formátu sortable ("s")
    2. "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.' FFFFFFF"
  4. "'Celé datum''T'Time hour'':'Minute'''Time offset''

    1. "yyyy'-'MM'-'dd'T'HH':'mmZ"
    2. "yyyy'-'MM'-'dd'T'HH':'mm('+'/'-')HH':'mm"
  5. Datum a čas

    1. "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
    2. "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.' FFFFFFFZ"
    3. "yyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'-')HH':'mm"
    4. "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.' FFFFFFF('+'/'-')HH':'mm"

    Tato úroveň členitosti je kompatibilní s DOKUMENTEM RFC 3339, široce používaným profilem ISO 8601 pro prokládání informací o datu a čase. Implementace však má několik omezení System.Text.Json .

    • RFC 3339 nezadá maximální počet desetinných číslic za sekundu, ale určuje, že alespoň jedna číslice musí následovat za tečkou, pokud je přítomen zlomek-druhý oddíl. Implementace umožňuje System.Text.Json až 16 číslic (pro podporu spolupráce s jinými programovacími jazyky a architekturami), ale parsuje pouze prvních sedm. Pokud při čtení DateTime a DateTimeOffset instancích existuje více než 16 desetinných sekund, bude vyvolán znak AJsonException.
    • RFC 3339 umožňuje znaky "T" a "Z" být "t" nebo "z", ale umožňuje aplikacím omezit podporu pouze na varianty velkého písmena. Implementace v System.Text.Json nich vyžaduje, aby byly "T" a "Z". A JsonException bude vyvolána, pokud vstupní datové části při čtení DateTime a DateTimeOffset instancích obsahují "t" nebo "z".
    • RFC 3339 určuje, že oddíly data a času jsou oddělené "T", ale umožňují aplikacím je oddělit mezerou (" "). System.Text.Json vyžaduje, aby oddíly data a času byly odděleny pomocí "T". Při čtení DateTime a DateTimeOffset instancích bude vyvolána funkce AJsonException, pokud vstupní datové části obsahují mezeru ("").

Pokud jsou desetinné zlomky pro sekundy, musí existovat alespoň jedna číslice. 2019-07-26T00:00:00. není povolená. I když je povoleno až 16 desetinných míst, parsuje se pouze prvních sedm. Cokoli, co je nad rámec toho, co je považováno za nulu. Například bude analyzováno, 2019-07-26T00:00:00.1234567890 jako by to bylo 2019-07-26T00:00:00.1234567. Tento přístup zachovává kompatibilitu DateTime s implementací, která je omezená na toto řešení.

Přestupné sekundy nejsou podporovány.

Podpora formátování

Pro formátování jsou definovány následující úrovně podrobností:

  1. "Úplné datum''T'Částečný čas'"

    1. "yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Specifikátor formátu sortable ("s")

      Slouží k formátování DateTime bez desetinných sekund a bez informací o posunu.

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

      Slouží k formátování DateTime s desetinnými sekundami, ale bez informací o posunu.

  2. Datum a čas

    1. "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"

      Používá se k formátování DateTime bez desetinných sekund, ale s posunem UTC.

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

      Slouží k formátování DateTime s desetinnými sekundami a posunem UTC.

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

      Slouží k formátování DateTime desetinných sekund nebo DateTimeOffset bez, ale s místním posunem.

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

      Slouží k formátování DateTime desetinných DateTimeOffset sekund a místního posunu.

    Tato úroveň členitosti odpovídá dokumentu RFC 3339.

Pokud reprezentace DateTime formátu odezvy nebo DateTimeOffset instance obsahuje koncové nuly v desetinných sekundách, pak JsonSerializer a Utf8JsonWriter naformátuje reprezentaci instance bez koncových nul. Například instance, DateTime jejíž reprezentace formátu odezvy je 2019-04-24T14:50:17.1010000Z, bude formátována jako 2019-04-24T14:50:17.101Z a JsonSerializer Utf8JsonWriter.

Pokud reprezentace DateTime formátu odezvy nebo DateTimeOffset instance obsahuje všechny nuly v desetinných sekundách, pak JsonSerializer Utf8JsonWriter naformátuje reprezentaci instance bez desetinných sekund. Například instance, DateTime jejíž reprezentace formátu odezvy je 2019-04-24T14:50:17.0000000+02:00, bude formátována jako 2019-04-24T14:50:17+02:00 a JsonSerializer Utf8JsonWriter.

Zkrácení nul v desetinných číslicích a sekundách umožňuje nejmenší výstup potřebný k zachování informací o zaokrouhlené cestě.

Zapisují se maximálně sedm desetinných a druhých číslic. Toto maximum odpovídá implementaci DateTime , která je omezená na toto řešení.