Aracılığıyla paylaş


System.Text.Json üzerinde DateTime ve DateTimeOffset desteği

Kitaplık, System.Text.Json ISO 8601-1:2019 genişletilmiş profiline göre ayrıştırıp yazar DateTime ve DateTimeOffset değerler oluşturur. Dönüştürücüler ile JsonSerializerseri hale getirme ve seri durumdan çıkarma için özel destek sağlar. Özel destek uygulamak için ve'yi Utf8JsonWriter de kullanabilirsinizUtf8JsonReader.

ISO 8601-1:2019 biçimi desteği

JsonSerializer, Utf8JsonReader, Utf8JsonWriterve JsonElement türleri, ISO 8601-1:2019 biçiminin genişletilmiş profiline göre ayrıştırıp yazma DateTime ve DateTimeOffset metin gösterimleri oluşturur. Örneğin, 2019-07-26T16:59:57-05:00.

DateTime ve DateTimeOffset verileri ile JsonSerializerseri hale getirilebilir:

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 ve DateTimeOffset ile JsonSerializerseri durumdan çıkarılabilir:

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

Varsayılan seçeneklerle, giriş DateTime ve DateTimeOffset metin gösterimleri genişletilmiş ISO 8601-1:2019 profiline uygun olmalıdır. Profile uymayan gösterimlerin seri durumdan çıkarılması, bir JsonExceptionoluşturmasına neden JsonSerializer olur:

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 ve DateTimeOffset gösterimleri dahil olmak üzere DateTime bir JSON yükünün içeriğine yapılandırılmış erişim sağlar. Aşağıdaki örnekte, bir sıcaklık koleksiyonundan Pazartesi günleri ortalama sıcaklığın nasıl hesaplanması gösterilmektedir:

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

Uyumlu DateTime olmayan gösterimlere sahip bir yük verilen ortalama sıcaklığı hesaplamaya çalışmak bir FormatExceptionoluşturmasına neden JsonDocument olur:

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()

Alt düzey Utf8JsonWriter yazma işlemleri DateTime ve DateTimeOffset veriler:

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 ayrıştırmalar DateTime ve DateTimeOffset veriler:

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

ile Utf8JsonReader uyumlu olmayan biçimleri okumaya çalışmak, bir oluşturmasına FormatExceptionneden olur:

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 ve TimeOnly özelliklerini seri hale getirme

.NET 7+ ile serileştirmeyi System.Text.Json ve seri durumdan kaldırmayı DateOnly ve TimeOnly türleri destekler. Aşağıdaki nesneyi göz önünde bulundurun:

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

Aşağıdaki örnek bir Appointment nesneyi serileştirir, sonuçta elde edilen JSON'yi görüntüler ve ardından türün yeni bir örneğine geri seri durumdan Appointment çıkartır. Son olarak, özgün ve yeni seri durumdan çıkarılmış örnekler eşitlik için karşılaştırılır ve sonuçlar konsola yazılır:

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

Önceki kodda:

  • Bir Appointment nesne örneği oluşturulur ve değişkene appointment atanır.
  • appointment Örneği kullanılarak JsonSerializer.SerializeJSON'a seri hale getirilir.
  • Sonuçta elde edilen JSON konsola yazılır.
  • JSON, kullanılarak JsonSerializer.Deserializetürünün yeni bir örneğine seri durumdan Appointment çıkarılır.
  • Özgün ve yeni seri durumdan çıkarılmış örnekler eşitlik için karşılaştırılır.
  • Karşılaştırmanın sonucu konsola yazılır.

ve için DateTime özel destek DateTimeOffset

Kullanırken JsonSerializer

Seri hale getiricinin özel ayrıştırma veya biçimlendirme gerçekleştirmesini istiyorsanız, özel dönüştürücüler uygulayabilirsiniz. İşte birkaç örnek:

DateTime(Offset). Ayrıştır ve DateTime(Uzaklık). ToString

Giriş DateTime veya DateTimeOffset metin gösterimlerinizin biçimlerini belirleyemiyorsanız, dönüştürücü okuma mantığınızda yöntemini kullanabilirsiniz DateTime(Offset).Parse . Bu yöntem kullanmanıza olanak tanır. NET'in, GENIŞLETILMIŞ ISO 8601-1:2019 profiline uymayan ISO 8601 dışı dizeler ve ISO 8601 biçimleri dahil olmak üzere çeşitli DateTimeDateTimeOffset ve metin biçimlerini ayrıştırmaya yönelik kapsamlı desteği. Bu yaklaşım, seri hale getiricinin yerel uygulamasını kullanmaktan daha az performanslıdır.

Seri hale getirme için dönüştürücü yazma mantığınızda yöntemini kullanabilirsiniz DateTime(Offset).ToString . Bu yöntem, standart tarih ve saat biçimlerinden herhangi birini ve DateTimeOffset özel tarih ve saat biçimlerini kullanarak yazmanızı DateTime ve değerleri yazmanızı sağlar. Bu yaklaşım ayrıca seri hale getiricinin yerel uygulamasını kullanmaktan daha az performanslıdır.

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"

Not

ve typeToConvertTDateTimeuygulanırken JsonConverter<T>parametresi her zaman olur.typeof(DateTime) parametresi, çok biçimli durumların işlenmesinde ve performans açısından genel değerlerin typeof(T) kullanılmasında kullanışlıdır.

Utf8Parser ve Utf8Formatter

Giriş DateTime veya metin gösterimleriniz "R", "l", "O" veya DateTimeOffset "G" standart tarih ve saat biçim dizelerinden biriyle uyumluysa veya bu biçimlerden birine göre yazmak istiyorsanız, dönüştürücü mantığınızda hızlı UTF-8 tabanlı ayrıştırma ve biçimlendirme yöntemlerini kullanabilirsiniz. Bu yaklaşım, sDateTime(Offset).Parse ve DateTime(Offset).ToStringkullanmaktan çok daha hızlıdır.

Aşağıdaki örnekte, değerleri "R" standart biçimine göre seri hale getiren ve seri durumdan çıkaran DateTime özel bir dönüştürücü gösterilmektedir:

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"

Not

"R" standart biçimi her zaman 29 karakter uzunluğunda olacaktır.

"l" (küçük harf "L") biçimi, yalnızca ve Utf8Formatter türleri tarafından Utf8Parser desteklendiği için diğer standart tarih ve saat biçimi dizeleriyle belgelenmez. Biçim küçük harf RFC 1123'tür ("R" biçiminin küçük harfli sürümü). Örneğin, "per, 25 temmuz 2019 06:36:07 gmt".

DateTime(Offset) kullanın. Geri dönüş olarak ayrıştırma

Giriş DateTime veya DateTimeOffset verilerinizin genişletilmiş ISO 8601-1:2019 profiline uymasını bekliyorsanız, seri hale getiricinin yerel ayrıştırma mantığını kullanabilirsiniz. Geri dönüş mekanizması da uygulayabilirsiniz. Aşağıdaki örnekte, kullanarak TryGetDateTime(DateTime)bir DateTime metin gösterimi ayrıştırma başarısız olduktan sonra dönüştürücüsü kullanarak Parse(String)verileri başarıyla ayrıştırmaktadır:

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"

Unix dönem tarih biçimini kullanma

Aşağıdaki dönüştürücüler Unix dönem biçimini saat dilimi uzaklığı (veya /Date(1590863400000)/gibi değerler) /Date(1590863400000-0700)/ ile veya olmadan işler:

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

Kullanırken Utf8JsonWriter

ile Utf8JsonWriterbir özel DateTime veya DateTimeOffset metin gösterimi yazmak istiyorsanız, özel gösteriminizi bir String, , ReadOnlySpan<Byte>ReadOnlySpan<Char>veya JsonEncodedTextolarak biçimlendirebilir ve ardından ilgili Utf8JsonWriter.WriteStringValue veya Utf8JsonWriter.WriteString yönteme geçirebilirsiniz.

Aşağıdaki örnekte özel bir DateTime biçimin ile nasıl oluşturulabileceği ToString(String, IFormatProvider) ve yöntemiyle nasıl yazılacağı gösterilmektedir WriteStringValue(String) :

using System.Globalization;
using System.Text;
using System.Text.Json;

public class Example
{
    public static void Main(string[] args)
    {
        var options = new JsonWriterOptions
        {
            Indented = true
        };

        using (var stream = new MemoryStream())
        {
            using (var writer = new Utf8JsonWriter(stream, options))
            {
                string dateStr = DateTime.UtcNow.ToString("F", CultureInfo.InvariantCulture);

                writer.WriteStartObject();
                writer.WriteString("date", dateStr);
                writer.WriteNumber("temp", 42);
                writer.WriteEndObject();
            }

            string json = Encoding.UTF8.GetString(stream.ToArray());
            Console.WriteLine(json);
        }
    }
}

// The example displays output similar to the following:
// {
//     "date": "Tuesday, 27 August 2019 19:21:44",
//     "temp": 42
// }

Kullanırken Utf8JsonReader

ile Utf8JsonReaderbir özel DateTime veya DateTimeOffset metin gösterimi okumak istiyorsanız, geçerli JSON belirtecinin değerini kullanarak GetString() yöntemi String olarak alabilir ve ardından özel mantık kullanarak değeri ayrıştırabilirsiniz.

Aşağıdaki örnek, yöntemi kullanılarak özel DateTimeOffset metin gösteriminin GetString() nasıl alınabileceğini ve ardından kullanılarak ParseExact(String, String, IFormatProvider)ayrıştırılabildiğini gösterir:

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

System.Text.Json'da genişletilmiş ISO 8601-1:2019 profili

Tarih ve saat bileşenleri

'de System.Text.Json uygulanan genişletilmiş ISO 8601-1:2019 profili, tarih ve saat gösterimleri için aşağıdaki bileşenleri tanımlar. Bu bileşenler, ayrıştırma, biçimlendirme DateTime ve DateTimeOffset gösterimler sırasında desteklenen çeşitli ayrıntı düzeylerini tanımlamak için kullanılır.

Bileşen Biçimlendir Açıklama
Year "yyyy" 0001-9999
Month "AA" 01-12
Gün "dd" 01-28, 01-29, 01-30, 01-31 ay/yıl temelinde.
Saat "HH" 00-23
Dakika "mm" 00-59
Second "ss" 00-59
İkinci kesir "FFFFFFF" En az bir basamak, en fazla 16 basamak.
Zaman farkı "K" "Z" veya "('+'/'-')HH':'mm".
Kısmi süre "HH':'mm':'ss[FFFFFFF]" UTC uzaklık bilgisi olmayan saat.
Tam tarih "yyyy'-'MM'-'dd" Takvim tarihi.
Tam zamanlı "'Kısmi zaman'K" Yerel saat ile UTC arasında saat uzaklığı ile günün UTC veya Yerel saat.
Tarih saat "'Tam tarih''T''Tam saat'" Takvim tarihi ve saati, örneğin, 2019-07-26T16:59:57-05:00.

Ayrıştırma desteği

Ayrıştırma için aşağıdaki ayrıntı düzeyleri tanımlanır:

  1. 'Tam tarih'

    1. "yyyy'-'MM'-'dd"
  2. "'Tam tarih'''T''Hour'':''Minute'"

    1. "yyyy'-'MM'-'dd'T'HH':'mm"
  3. "'Tam tarih'''T''Kısmi saat'"

    1. "yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Sıralanabilir ("s") Biçim Tanımlayıcısı)
    2. "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.' FFFFFFF"
  4. "'Tam tarih'''T''Saat saat'':''Minute'''Saat uzaklığı'"

    1. "yyyy'-'MM'-'dd'T'HH':'mmZ"
    2. "yyyy'-'MM'-'dd'T'HH':'mm('+'/'-')HH':'mm"
  5. 'Tarih saat'

    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"

    Bu ayrıntı düzeyi, tarih ve saat bilgilerinin değişimi için kullanılan ve iso 8601'in yaygın olarak benimsenen bir profili olan RFC 3339 ile uyumludur. Ancak, uygulamada birkaç kısıtlama System.Text.Json vardır.

    • RFC 3339, kesirli saniye basamak sayısı üst sınırını belirtmez, ancak kesirli saniye bölümü varsa en az bir rakamın dönemi izlemesi gerektiğini belirtir. içindeki System.Text.Json uygulaması en fazla 16 basamağı (diğer programlama dilleri ve çerçeveleriyle birlikte çalışma desteği için) sağlar, ancak yalnızca ilk yediyi ayrıştırmaktadır. JsonException Okuma DateTime ve DateTimeOffset örnekler sırasında 16'dan fazla kesirli ikinci basamak varsa bir oluşturulur.
    • RFC 3339, "T" ve "Z" karakterlerinin sırasıyla "t" veya "z" olmasını sağlar, ancak uygulamaların desteği yalnızca büyük harf çeşitlemeleriyle sınırlamasına olanak tanır. içindeki System.Text.Json uygulaması için "T" ve "Z" olması gerekir. JsonException Giriş yükleri okuma DateTime ve DateTimeOffset örnekler sırasında "t" veya "z" içeriyorsa bir oluşturulur.
    • RFC 3339, tarih ve saat bölümlerinin "T" ile ayrıldığını belirtir, ancak uygulamaların bunları boşlukla (" ") ayırmasına izin verir. System.Text.Json tarih ve saat bölümlerinin "T" ile ayrılmasını gerektirir. JsonException Giriş yükleri okuma DateTime ve DateTimeOffset örnekler sırasında boşluk (" ") içeriyorsa bir oluşturulur.

Saniyeler için ondalık kesirler varsa, en az bir basamak olmalıdır. 2019-07-26T00:00:00. izin verilmiyor. En fazla 16 kesirli basamağı kullanabilirsiniz ancak yalnızca ilk yedi basamak ayrıştırılır. Bunun ötesindeki her şey sıfır olarak kabul edilir. Örneğin, 2019-07-26T00:00:00.1234567890 gibi ayrıştırılır 2019-07-26T00:00:00.1234567. Bu yaklaşım, bu çözümle sınırlı olan uygulamayla DateTime uyumluluğu korur.

Artık saniyeler desteklenmez.

Biçimlendirme desteği

Biçimlendirme için aşağıdaki ayrıntı düzeyleri tanımlanır:

  1. "'Tam tarih'''T''Kısmi saat'"

    1. "yyyy'-'MM'-'dd'T'HH':'mm':'ss" (Sıralanabilir ("s") Biçim Tanımlayıcısı)

      Kesirli saniyeler olmadan ve uzaklık bilgisi olmadan biçimlendirmek DateTime için kullanılır.

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

      Kesirli saniyelerle ama uzaklık bilgisi olmadan biçimlendirmek DateTime için kullanılır.

  2. 'Tarih saat'

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

      Kesirli saniye olmadan ancak UTC uzaklığıyla biçimlendirmek DateTime için kullanılır.

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

      Kesirli saniyelerle ve UTC uzaklığıyla biçimlendirmek DateTime için kullanılır.

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

      Kesirli saniyeler olmadan veya DateTimeOffset biçimlendirmek DateTime için kullanılır, ancak yerel uzaklık ile kullanılır.

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

      Kesirli saniyelerle ve yerel uzaklık ile veya DateTimeOffset biçimlendirmek DateTime için kullanılır.

    Bu ayrıntı düzeyi RFC 3339 ile uyumludur.

Bir DateTime veya DateTimeOffset örneğin gidiş dönüş biçimi gösteriminde kesirli saniyelerde JsonSerializer sonunda sıfırlar varsa ve Utf8JsonWriter sonunda sıfır olmadan örneğin bir gösterimini biçimlendirir. Örneğin, gidiş dönüş biçimi gösterimi olan 2019-04-24T14:50:17.1010000Zbir DateTime örnek ve Utf8JsonWritertarafından JsonSerializer olarak 2019-04-24T14:50:17.101Z biçimlendirilir.

Bir DateTime veya DateTimeOffset örneğin gidiş dönüş biçimi gösteriminde kesirli saniyelerde sıfırlar varsa ve Utf8JsonWriter kesirli saniyeler JsonSerializer olmadan örneğin gösterimini biçimlendirir. Örneğin, gidiş dönüş biçimi gösterimi olan 2019-04-24T14:50:17.0000000+02:00bir DateTime örnek ve Utf8JsonWritertarafından JsonSerializer olarak 2019-04-24T14:50:17+02:00 biçimlendirilir.

Kesirli saniye basamaklarında sıfırların kesilmesi, bir gidiş dönüşteki bilgilerin yazılması için gereken en küçük çıkışı sağlar.

En fazla yedi kesirli saniye basamağı yazılır. Bu üst sınır, bu çözümle sınırlı olan uygulamayla DateTime hizalanır.