Dela via


Stöd för DateTime och DateTimeOffset i System.Text.Json

Biblioteket System.Text.Json parsar och skriver DateTime och DateTimeOffset värden enligt den utökade profilen ISO 8601-1:2019. Konverterare har anpassat stöd för serialisering och deserialisering med JsonSerializer. Du kan också använda Utf8JsonReader och Utf8JsonWriter implementera anpassad support.

Stöd för FORMATET ISO 8601-1:2019

Typerna JsonSerializer, Utf8JsonReader, Utf8JsonWriteroch JsonElement parsar och skriver DateTime och DateTimeOffset text enligt den utökade profilen för FORMATET ISO 8601-1:2019. Exempel: 2019-07-26T16:59:57-05:00

DateTime och DateTimeOffset data kan serialiseras med 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 och DateTimeOffset kan också deserialiseras med 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

Med standardalternativ måste indata DateTime - och DateTimeOffset textrepresentationer överensstämma med den utökade ISO 8601-1:2019-profilen. Om du försöker deserialisera representationer som inte överensstämmer med profilen genereras JsonSerializer en JsonException:

using System.Text.Json;

public class Example
{
    private class Product
    {
        public string? Name { get; set; }
        public DateTime ExpiryDate { get; set; }
    }

    public static void Main(string[] args)
    {
        string json = @"{""Name"":""Banana"",""ExpiryDate"":""26/07/2019""}";
        try
        {
            Product _ = JsonSerializer.Deserialize<Product>(json)!;
        }
        catch (JsonException e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

// The example displays the following output:
// The JSON value could not be converted to System.DateTime. Path: $.ExpiryDate | LineNumber: 0 | BytePositionInLine: 42.

JsonDocument Ger strukturerad åtkomst till innehållet i en JSON-nyttolast, inklusive DateTime och DateTimeOffset representationer. I följande exempel visas hur du beräknar genomsnittstemperaturen på måndagar från en samling temperaturer:

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

Om du försöker beräkna den genomsnittliga temperaturen med tanke på en nyttolast med icke-kompatibla DateTime representationer genereras JsonDocument en 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()

Skrivningar DateTime och DateTimeOffset data på lägre nivåUtf8JsonWriter:

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 parsningar DateTime och 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

Om du försöker läsa icke-kompatibla format med Utf8JsonReader genereras en 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()

Serialisera egenskaperna DateOnly och TimeOnly

Med .NET 7+, System.Text.Json stöder serialisering och deserialisering DateOnly och TimeOnly typer. Tänk på följande objekt:

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

I följande exempel serialiseras ett Appointment objekt, den resulterande JSON visas och sedan deserialiseras det tillbaka till en ny instans av Appointment typen. Slutligen jämförs de ursprungliga och nyligen deserialiserade instanserna för likhet och resultaten skrivs till konsolen:

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

I koden ovan:

  • Ett Appointment objekt instansieras och tilldelas till variabeln appointment .
  • Instansen appointment serialiseras till JSON med hjälp av JsonSerializer.Serialize.
  • Den resulterande JSON-filen skrivs till konsolen.
  • JSON deserialiseras tillbaka till en ny instans av typen Appointment med hjälp JsonSerializer.Deserializeav .
  • De ursprungliga och nyligen deserialiserade instanserna jämförs för likhet.
  • Resultatet av jämförelsen skrivs till konsolen.

Anpassat stöd för DateTime och DateTimeOffset

När du använder JsonSerializer

Om du vill att serialiseraren ska utföra anpassad parsning eller formatering kan du implementera anpassade konverterare. Några exempel:

DateTime(offset). Parsa och DateTime(offset). ToString

Om du inte kan fastställa formaten för dina indata DateTime - eller DateTimeOffset textrepresentationer kan du använda DateTime(Offset).Parse metoden i konverterarens läslogik. Med den här metoden kan du använda . NET:s omfattande stöd för parsning av olika DateTime format och DateTimeOffset textformat, inklusive icke-ISO 8601-strängar och ISO 8601-format som inte överensstämmer med den utökade ISO 8601-1:2019-profilen. Den här metoden är mindre högpresterande än att använda serialiserarens interna implementering.

För serialisering kan du använda DateTime(Offset).ToString metoden i konverterarens skrivlogik. Med den här metoden kan du skriva DateTime och värden med något av standardformaten för datum och tid samt anpassade datum- och tidsformatDateTimeOffset. Den här metoden är också mindre högpresterande än att använda serialiserarens interna implementering.

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"

Kommentar

När du implementerar JsonConverter<T>, och T är DateTime, kommer parametern typeToConvert alltid att vara typeof(DateTime). Parametern är användbar för att hantera polymorfa fall och när du använder generiska läkemedel för att komma typeof(T) på ett högpresterande sätt.

Utf8Parser och Utf8Formatter

Du kan använda snabba UTF-8-baserade parsnings- och formateringsmetoder i konverterarlogik om dina indataDateTime- eller DateTimeOffset textrepresentationer är kompatibla med någon av standardsträngarna "R", "l", "O" eller "G" standardformat, eller om du vill skriva enligt något av dessa format. Den här metoden är mycket snabbare än att använda DateTime(Offset).Parse och DateTime(Offset).ToString.

I följande exempel visas en anpassad konverterare som serialiserar och deserialiserar DateTime värden enligt standardformatet "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"

Kommentar

Standardformatet R är alltid 29 tecken långt.

Formatet "l" (gemener "L") dokumenteras inte med de andra standardformatsträngarna för datum och tid eftersom det endast stöds av typerna Utf8Parser och Utf8Formatter . Formatet är gement RFC 1123 (en gemen version av R-formatet). Till exempel "tor, 25 jul 2019 06:36:07 gmt".

Använd DateTime(offset). Parsa som reserv

Om du vanligtvis förväntar dig att dina indata DateTime eller DateTimeOffset data överensstämmer med den utökade ISO 8601-1:2019-profilen kan du använda serialiserarens interna parsningslogik. Du kan också implementera en återställningsmekanism. I följande exempel visas att konverteraren parsar data med : efter att ha misslyckats med att parsa en DateTime textrepresentation med hjälp TryGetDateTime(DateTime)av 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"

Använda Unix epoch-datumformat

Följande konverterare hanterar Unix epokformat med eller utan tidszonsförskjutning (värden som /Date(1590863400000-0700)/ eller /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);
    }
}

När du använder Utf8JsonWriter

Om du vill skriva en anpassad DateTime representation eller DateTimeOffset textrepresentation med Utf8JsonWriterkan du formatera din anpassade representation till en String, ReadOnlySpan<Byte>, ReadOnlySpan<Char>eller , och JsonEncodedTextsedan skicka den till motsvarande Utf8JsonWriter.WriteStringValue eller Utf8JsonWriter.WriteString metod.

I följande exempel visas hur ett anpassat DateTime format kan skapas med ToString(String, IFormatProvider) och sedan skrivas med WriteStringValue(String) metoden:

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

När du använder Utf8JsonReader

Om du vill läsa en anpassad DateTime representation eller DateTimeOffset textrepresentation med Utf8JsonReaderkan du hämta värdet för den aktuella JSON-token som en String användningsmetod GetString() och sedan parsa värdet med hjälp av anpassad logik.

I följande exempel visas hur en anpassad DateTimeOffset textrepresentation kan hämtas med hjälp av GetString() metoden och sedan parsas med :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

Den utökade ISO 8601-1:2019-profilen i System.Text.Json

Datum- och tidskomponenter

Den utökade ISO 8601-1:2019-profilen som implementeras i System.Text.Json definierar följande komponenter för datum- och tidsrepresentationer. Dessa komponenter används för att definiera olika nivåer av kornighet som stöds vid parsning och formatering DateTime och DateTimeOffset representationer.

Komponent Format beskrivning
Year "yyyyy" 0001-9999
Månad "MM" 01-12
Dag "dd" 01-28, 01-29, 01-30, 01-31 baserat på månad/år.
Tid "HH" 00-23
Minut "mm" 00-59
Second "ss" 00-59
Andra bråket "FFFFFFF" Minst en siffra, högst 16 siffror.
Tidsförskjutning "K" Antingen "Z" eller "('+'/'-')HH':'mm".
Partiell tid "HH':'mm':'ss[FFFFFFF]" Tid utan UTC-förskjutningsinformation.
Fullständigt datum "åååå'-'MM'-'dd" Kalenderdatum.
Heltid "'Partiell tid'K" UTC på dagen eller lokal tid på dagen med tidsförskjutningen mellan lokal tid och UTC.
DateTime "'Fullständigt datum'T'Heltid'" Kalenderdatum och tid på dagen, till exempel 2019-07-26T16:59:57-05:00.

Stöd för parsning

Följande kornighetsnivåer definieras för parsning:

  1. "Fullständigt datum"

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

    1. "åååå'-'MM'-'dd'T'HH':'mm"
  3. "'Fullständigt datum'T''Partiell tid'"

    1. "åååå'-'MM'-'dd'T'HH':'mm':'ss" (Den sorterbara ("s") formatspecificeraren)
    2. "åååå'-'MM'-'dd'T'HH':'mm':'ss'.' FFFFFFF"
  4. "'Fullständigt datum''T''Tidstim''':'Minut''Tidsförskjutning'"

    1. "åååå'-'MM'-'dd'T'HH':'mmZ"
    2. "åååå'-'MM'-'dd'T'HH':'mm('+'/'-')HH':'mm"
  5. Datumtid

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

    Den här detaljnivån är kompatibel med RFC 3339, en allmänt antagen profil för ISO 8601 som används för att ändra datum- och tidsinformation. Det finns dock några begränsningar i implementeringen System.Text.Json .

    • RFC 3339 anger inte ett maximalt antal bråksekunderssiffror, men anger att minst en siffra måste följa perioden, om det finns ett bråksekundersavsnitt. Implementeringen i System.Text.Json tillåter upp till 16 siffror (för att stödja interop med andra programmeringsspråk och ramverk), men parsar bara de första sju. A JsonException utlöses om det finns fler än 16 bråksiffriga sekundsiffror vid läsning DateTime och DateTimeOffset instanser.
    • RFC 3339 tillåter att tecknen "T" och "Z" är "t" respektive "z", men gör det möjligt för program att begränsa stödet till bara de övre varianterna. Implementeringen i System.Text.Json kräver att de är "T" och "Z". A JsonException utlöses om indatanyttolaster innehåller "t" eller "z" vid läsning DateTime och DateTimeOffset instanser.
    • RFC 3339 anger att datum- och tidsavsnitten avgränsas med "T", men tillåter att program separerar dem med ett blanksteg (" ") i stället. System.Text.Json kräver att datum- och tidsavsnitt avgränsas med "T". A JsonException utlöses om indatanyttolaster innehåller ett blanksteg (" ") när du läser DateTime och DateTimeOffset instanser.

Om det finns decimaltal för sekunder måste det finnas minst en siffra. 2019-07-26T00:00:00. tillåts inte. Upp till 16 bråksiffror tillåts, men endast de första sju parsas. Allt utöver det anses vara en nolla. Till exempel 2019-07-26T00:00:00.1234567890 parsas som om det vore 2019-07-26T00:00:00.1234567. Den här metoden bibehåller kompatibiliteten med implementeringen DateTime , vilket är begränsat till den här lösningen.

Skottsekunder stöds inte.

Stöd för formatering

Följande nivåer av kornighet definieras för formatering:

  1. "'Fullständigt datum'T''Partiell tid'"

    1. "åååå'-'MM'-'dd'T'HH':'mm':'ss" (Den sorterbara ("s") formatspecificeraren)

      Används för att formatera en DateTime utan bråk sekunder och utan förskjutningsinformation.

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

      Används för att formatera en DateTime med bråksekunder men utan förskjutningsinformation.

  2. Datumtid

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

      Används för att formatera en DateTime utan bråk sekunder men med en UTC-förskjutning.

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

      Används för att formatera en DateTime med bråksekunder och med en UTC-förskjutning.

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

      Används för att formatera en DateTime eller DateTimeOffset utan bråk sekunder men med en lokal förskjutning.

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

      Används för att formatera en DateTime eller DateTimeOffset med bråk sekunder och med en lokal förskjutning.

    Den här detaljnivån är kompatibel med RFC 3339.

Om rundresa-formatrepresentationen av en DateTime eller DateTimeOffset -instansen har avslutande nollor i bråksekunderna formateras JsonSerializer Utf8JsonWriter en representation av instansen utan avslutande nollor. En instans vars återgivningsformat är , formateras till exempel DateTime efter 2019-04-24T14:50:17.101Z JsonSerializer och Utf8JsonWriter.2019-04-24T14:50:17.1010000Z

Om rundresa-formatrepresentationen av en DateTime eller DateTimeOffset -instansen har alla nollor i bråksekunderna formateras JsonSerializer Utf8JsonWriter en representation av instansen utan bråksekunder. En instans vars återgivningsformat är , formateras till exempel DateTime efter 2019-04-24T14:50:17+02:00 JsonSerializer och Utf8JsonWriter.2019-04-24T14:50:17.0000000+02:00

Genom att trunkera nollor i bråksiffriga siffror kan du skriva de minsta utdata som behövs för att bevara information om en tur och retur-resa.

Högst sju bråksiffriga siffror skrivs. Det här maxvärdet överensstämmer med implementeringen DateTime , som är begränsad till den här lösningen.