Delen via


Ondersteuning voor DateTime en DateTimeOffset in System.Text.Json

De System.Text.Json bibliotheek parseert DateTime en schrijft en DateTimeOffset waarden volgens het uitgebreide ISO 8601-1:2019-profiel. Conversieprogramma's bieden aangepaste ondersteuning voor serialiseren en deserialiseren met JsonSerializer. U kunt ook aangepaste ondersteuning gebruiken Utf8JsonReader en Utf8JsonWriter implementeren.

Ondersteuning voor de ISO 8601-1:2019-indeling

De JsonSerializer, Utf8JsonReader, Utf8JsonWriteren JsonElement typen parseren en schrijven DateTime en DateTimeOffset tekstweergaven volgens het uitgebreide profiel van de ISO 8601-1:2019-indeling. Bijvoorbeeld: 2019-07-26T16:59:57-05:00.

DateTime en DateTimeOffset gegevens kunnen worden geserialiseerd met 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 en DateTimeOffset kan ook worden gedeserialiseerd met 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

Met standaardopties moeten invoer DateTime - en DateTimeOffset tekstweergaven voldoen aan het uitgebreide ISO 8601-1:2019-profiel. Als u probeert weergaven te deserialiseren die niet aan het profiel voldoen, wordt JsonSerializer het JsonExceptionvolgende veroorzaakt:

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.

Het JsonDocument biedt gestructureerde toegang tot de inhoud van een JSON-nettolading, inclusief DateTime en DateTimeOffset representaties. In het volgende voorbeeld ziet u hoe u de gemiddelde temperatuur op maandagen kunt berekenen vanaf een verzameling temperaturen:

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

Als u probeert de gemiddelde temperatuur te berekenen op basis van een nettolading met niet-compatibele DateTime representaties, veroorzaakt dit JsonDocument een 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()

Het lagere niveau Utf8JsonWriter schrijft DateTime en DateTimeOffset gegevens:

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 parseert DateTime en DateTimeOffset gegevens:

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

Als u niet-compatibele indelingen probeert te lezen, Utf8JsonReader wordt het volgende veroorzaakt 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- en TimeOnly-eigenschappen serialiseren

Met .NET 7+ System.Text.Json ondersteunt serialiseren en deserialiseren DateOnly en TimeOnly typen. Houd rekening met het volgende object:

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

In het volgende voorbeeld wordt een Appointment object geserialiseerd, wordt de resulterende JSON weergegeven en wordt het vervolgens weer gedeserialiseerd in een nieuw exemplaar van het Appointment type. Ten slotte worden de oorspronkelijke en nieuw gedeserialiseerde exemplaren vergeleken voor gelijkheid en worden de resultaten naar de console geschreven:

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

In de voorgaande code:

  • Een Appointment object wordt geïnstantieerd en toegewezen aan de appointment variabele.
  • Het appointment exemplaar wordt geserialiseerd naar JSON met behulp van JsonSerializer.Serialize.
  • De resulterende JSON wordt naar de console geschreven.
  • De JSON wordt gedeserialiseerd in een nieuw exemplaar van het Appointment type met behulp van JsonSerializer.Deserialize.
  • De oorspronkelijke en nieuw gedeserialiseerde instanties worden vergeleken voor gelijkheid.
  • Het resultaat van de vergelijking wordt naar de console geschreven.

Aangepaste ondersteuning voor DateTime en DateTimeOffset

Bij gebruik JsonSerializer

Als u wilt dat de serializer aangepaste parsering of opmaak uitvoert, kunt u aangepaste conversieprogramma's implementeren. Enkele voorbeelden:

DateTime(offset). Parseren en Datum/tijd(offset). ToString

Als u de notaties van uw invoer DateTime - of DateTimeOffset tekstweergaven niet kunt bepalen, kunt u de DateTime(Offset).Parse methode gebruiken in de leeslogica van uw conversieprogramma. Met deze methode kunt u . De uitgebreide ondersteuning van NET voor het parseren van verschillende DateTime en DateTimeOffset tekstindelingen, waaronder niet-ISO 8601-tekenreeksen en ISO 8601-indelingen die niet voldoen aan het uitgebreide ISO 8601-1:2019-profiel. Deze aanpak is minder goed dan het gebruik van de systeemeigen implementatie van de serializer.

Voor serialiseren kunt u de DateTime(Offset).ToString methode gebruiken in de schrijflogica van uw conversieprogramma. Met deze methode kunt u waarden schrijven en waarden schrijven DateTime met een van de standaardnotaties voor datum en tijd, en de aangepaste datum- en tijdnotaties.DateTimeOffset Deze aanpak is ook minder goed dan het gebruik van de systeemeigen implementatie van de serializer.

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"

Notitie

Bij het implementerenJsonConverter<T>, en T isDateTime, is typeof(DateTime)de typeToConvert parameter altijd. De parameter is handig voor het verwerken van polymorfe gevallen en bij het gebruik van generics om op een performante manier te komen typeof(T) .

Utf8Parser en Utf8Formatter

U kunt snelle parserings- en opmaakmethoden op basis van UTF-8 in uw conversieprogrammalogica gebruiken als uw invoerDateTime- of DateTimeOffset tekstweergaven compatibel zijn met een van de tekenreeksen 'R', 'l', 'O' of 'G', of als u wilt schrijven op basis van een van deze indelingen. Deze aanpak is veel sneller dan het gebruik DateTime(Offset).Parse en DateTime(Offset).ToString.

In het volgende voorbeeld ziet u een aangepast conversieprogramma waarmee waarden worden geserialiseerd en gedeserialiseerd DateTime volgens de standaardindeling 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"

Notitie

De standaardindeling R is altijd 29 tekens lang.

De indeling 'l' (kleine letter 'L') wordt niet gedocumenteerd met de andere standaardtekenreeksen voor datum- en tijdnotatie, omdat deze alleen wordt ondersteund door de Utf8Parser en Utf8Formatter typen. De indeling is RFC 1123 (een kleine letter van de R-indeling). Bijvoorbeeld 'do, 25 juli 2019 06:36:07 gmt'.

Gebruik Datum/tijd(verschuiving). Parseren als een terugval

Als u verwacht dat uw invoer DateTime of DateTimeOffset gegevens voldoen aan het uitgebreide ISO 8601-1:2019-profiel, kunt u de systeemeigen parseringslogica van de serializer gebruiken. U kunt ook een terugvalmechanisme implementeren. In het volgende voorbeeld ziet u dat na het parseren van een DateTime tekstweergave met behulp van TryGetDateTime(DateTime)het conversieprogramma de gegevens met succes parseert met behulp van 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"

Datumnotatie van Unix-tijdvakken gebruiken

De volgende conversieprogramma's verwerken de Unix-tijdsperiode-indeling met of zonder een tijdzoneverschil (waarden zoals /Date(1590863400000-0700)/ of /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);
    }
}

Bij gebruik Utf8JsonWriter

Als u een aangepaste DateTime of DateTimeOffset tekstweergave wilt schrijven met Utf8JsonWriter, kunt u de aangepaste weergave opmaken in een String, ReadOnlySpan<Byte>, ReadOnlySpan<Char>of JsonEncodedText, en deze vervolgens doorgeven aan de bijbehorende Utf8JsonWriter.WriteStringValue of Utf8JsonWriter.WriteString methode.

In het volgende voorbeeld ziet u hoe een aangepaste DateTime indeling kan worden gemaakt met ToString(String, IFormatProvider) en vervolgens met de WriteStringValue(String) methode kan worden geschreven:

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

Bij gebruik Utf8JsonReader

Als u een aangepaste DateTime of DateTimeOffset tekstweergave wilt lezen, Utf8JsonReaderkunt u de waarde van het huidige JSON-token ophalen als een String methode GetString() en vervolgens de waarde parseren met behulp van aangepaste logica.

In het volgende voorbeeld ziet u hoe een aangepaste DateTimeOffset tekstweergave kan worden opgehaald met behulp van de GetString() methode en vervolgens geparseerd met: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

Het uitgebreide ISO 8601-1:2019-profiel in System.Text.Json

Datum- en tijdonderdelen

Het uitgebreide ISO 8601-1:2019-profiel dat is geïmplementeerd in System.Text.Json definieert de volgende onderdelen voor datum- en tijdweergaven. Deze onderdelen worden gebruikt om verschillende ondersteunde granulariteitsniveaus te definiëren bij het parseren en opmaken en DateTimeOffset weergevenDateTime.

Onderdeel Opmaak Beschrijving
Year "yyyy" 0001-9999
Month "MM" 01-12
Dag "dd" 01-28, 01-29, 01-30, 01-31 op basis van maand/jaar.
Uur "UU" 00-23
Minuut "mm" 00-59
Seconde "ss" 00-59
Tweede breuk "FFFFFFF" Minimaal één cijfer, maximaal 16 cijfers.
Tijdsverschil "K" Ofwel 'Z' of '('+'/'-')HH':'mm'.
Gedeeltelijke tijd "UU':'mm':'ss[FFFFFFF]" Tijd zonder UTC-offsetgegevens.
Volledige datum "jjjj"-'MM'-'dd" Kalenderdatum.
Fulltime "Gedeeltelijke tijd'K" UTC van de dag of lokale tijd van de dag met de tijdverschil tussen lokale tijd en UTC.
Datum en tijd "Full date'T'T'Full time'" Kalenderdatum en -tijd van dag, bijvoorbeeld 2019-07-26T16:59:57-05:00.

Ondersteuning voor parseren

De volgende granulariteitsniveaus worden gedefinieerd voor parseren:

  1. 'Volledige datum'

    1. "jjjj"-'MM'-'dd"
  2. "'Full date''T'Hour'':'Minute'"

    1. "jjjj"-'MM'-'dd'T'UU':'mm"
  3. "'Volledige datum'T''Gedeeltelijke tijd''

    1. "jjjj'-'MM'-'dd'T'HH':'mm':'ss" (De sorteerbare ("s") Opmaakaanduiding)
    2. "jjjj"-'MM'-'dd'T'HH':'mm':'ss'.' FFFFFFF"
  4. "'Full date''T'Time hour'':'Minute'Time offset''

    1. "jjjj"-'MM'-'dd'T'UU':'mmZ"
    2. "jjjj"-'MM'-'dd'T'UU':'mm('+'/')HH':'mm'
  5. 'Datum/tijd'

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

    Dit granulariteitsniveau voldoet aan RFC 3339, een breed geaccepteerd profiel van ISO 8601 dat wordt gebruikt voor het wisselen van datum- en tijdgegevens. Er zijn echter enkele beperkingen in de System.Text.Json implementatie.

    • RFC 3339 geeft geen maximumaantal fractionele-seconde cijfers op, maar geeft aan dat ten minste één cijfer de periode moet volgen, als er een breuk-tweede sectie aanwezig is. De implementatie in System.Text.Json staat maximaal 16 cijfers toe (ter ondersteuning van interop met andere programmeertalen en frameworks), maar parseert alleen de eerste zeven. Er wordt een JsonException gegenereerd als er meer dan 16 fractionele tweede cijfers zijn bij het lezen DateTime en DateTimeOffset exemplaren.
    • RFC 3339 staat toe dat de tekens 'T' en 'Z' respectievelijk 't' of 'z' zijn, maar toepassingen kunnen ondersteuning beperken tot alleen de hoofdlettervarianten. Voor de implementatie System.Text.Json moeten ze 'T' en 'Z' zijn. Er wordt een JsonException gegenereerd als invoerpayloads 't' of 'z' bevatten bij het lezen DateTime en DateTimeOffset exemplaren.
    • RFC 3339 geeft aan dat de datum- en tijdsecties worden gescheiden door 'T', maar in plaats daarvan kunnen toepassingen ze scheiden door een spatie (" ") . System.Text.Json vereist dat datum- en tijdsecties worden gescheiden met 'T'. Er JsonException wordt een gegenereerd als invoerpayloads een spatie (" ") bevatten bij het lezen DateTime en DateTimeOffset exemplaren.

Als er seconden decimale breuken zijn, moet er ten minste één cijfer zijn. 2019-07-26T00:00:00. is niet toegestaan. Hoewel maximaal 16 fractionele cijfers zijn toegestaan, worden alleen de eerste zeven geparseerd. Alles buiten dat wordt beschouwd als een nul. Wordt bijvoorbeeld 2019-07-26T00:00:00.1234567890 geparseerd alsof het is 2019-07-26T00:00:00.1234567. Deze aanpak behoudt de compatibiliteit met de DateTime implementatie, die beperkt is tot deze resolutie.

Leap-seconden worden niet ondersteund.

Ondersteuning voor opmaak

De volgende granulariteitsniveaus worden gedefinieerd voor opmaak:

  1. "'Volledige datum'T''Gedeeltelijke tijd''

    1. "jjjj'-'MM'-'dd'T'HH':'mm':'ss" (De sorteerbare ("s") Opmaakaanduiding)

      Wordt gebruikt voor het opmaken van een DateTime zonder breuk seconden en zonder offsetgegevens.

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

      Wordt gebruikt voor het opmaken van een DateTime met fractionele seconden, maar zonder offsetgegevens.

  2. 'Datum/tijd'

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

      Wordt gebruikt voor het opmaken van een DateTime zonder breuk seconden, maar met een UTC-offset.

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

      Wordt gebruikt voor het opmaken van een DateTime met fractionele seconden en met een UTC-offset.

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

      Wordt gebruikt voor het opmaken van een DateTime of DateTimeOffset zonder fractionele seconden, maar met een lokale offset.

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

      Wordt gebruikt voor het opmaken van een DateTime of DateTimeOffset met fractionele seconden en met een lokale offset.

    Dit granulariteitsniveau voldoet aan RFC 3339.

Als de weergave van een of meer retournaties van een DateTime of DateTimeOffset exemplaar volgnullen bevat in de fractionele seconden, JsonSerializer Utf8JsonWriter wordt een weergave van het exemplaar opgemaakt zonder volgnullen. Een exemplaar waarvan de weergave van de retour-reisindeling is2019-04-24T14:50:17.1010000Z, wordt bijvoorbeeld DateTime opgemaakt als 2019-04-24T14:50:17.101Z door JsonSerializer enUtf8JsonWriter.

Als de weergave van de retourindeling van een DateTime of DateTimeOffset exemplaar alle nullen in de fractionele seconden heeft, JsonSerializer Utf8JsonWriter wordt een weergave van het exemplaar opgemaakt zonder breuken seconden. Een exemplaar waarvan de weergave van de retour-reisindeling is2019-04-24T14:50:17.0000000+02:00, wordt bijvoorbeeld DateTime opgemaakt als 2019-04-24T14:50:17+02:00 door JsonSerializer enUtf8JsonWriter.

Door nullen in fractionele-seconde cijfers af te kapen, kan de kleinste uitvoer die nodig is om informatie over een retour te bewaren, worden weggeschreven.

Er worden maximaal zeven fractionele-seconde cijfers geschreven. Dit maximum komt overeen met de DateTime implementatie, die beperkt is tot deze resolutie.