System.Text.Json의 DateTime 및 DateTimeOffset 지원

System.string 라이브러리는 DateTime DateTimeOffset ISO 8601-1:2019 확장 프로필에 따라 및 값을 구문 분석 하 고 기록 합니다. 변환기 는로 serialize 및 deserialize 할 수 있는 사용자 지정 지원을 제공 JsonSerializer 합니다. 및를 사용 하는 경우에도 사용자 지정 지원을 구현할 수 있습니다 Utf8JsonReader Utf8JsonWriter .

ISO 8601-1:2019 형식에 대 한 지원

JsonSerializer,, Utf8JsonReader Utf8JsonWriterJsonElement 형식은 DateTime DateTimeOffset ISO 8601-1:2019 형식의 확장 된 프로필에 따라 구문 분석 및 쓰기 및 텍스트 표현을 나타냅니다 (예: 2019-07-26t16:59:57-05:00).

DateTimeDateTimeOffset다음을 사용 하 여 및 데이터를 직렬화 할 수 있습니다 JsonSerializer .

using System;
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"}

다음을 사용 하 여 deserialize 할 수도 있습니다 JsonSerializer .

using System;
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

기본 옵션을 사용 하 여 입력 DateTimeDateTimeOffset 텍스트 표현은 확장 된 ISO 8601-1:2019 프로필을 준수 해야 합니다. 프로필에 맞지 않는 표현을 deserialize 하려고 하면이 JsonSerializer throw 됩니다 JsonException .

using System;
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 및 표현을 포함 하 여 JSON 페이로드의 내용에 대 한 구조적 액세스를 제공 합니다 DateTime DateTimeOffset . 아래 예제에서는 온도 수집이 지정 된 경우 월요일의 평균 온도를 계산할 수 있는 방법을 보여 줍니다.

using System;
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

비준수 표현이 포함 된 페이로드에 대해 평균 온도를 계산 하려고 시도 하면 DateTime 이 throw 됩니다 JsonDocument FormatException .

using System;
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()

낮은 수준에서 Utf8JsonWriter 및 데이터를 기록 합니다 DateTime DateTimeOffset .

using System;
using System.IO;
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 구문 분석 DateTimeDateTimeOffset 데이터:

using System;
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

호환 되지 않는 형식을로 읽으려고 하면 Utf8JsonReader 이 throw 됩니다 FormatException .

using System;
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()

및에 대 한 사용자 지정 지원 DateTimeDateTimeOffset

사용 하는 경우 JsonSerializer

Serializer에서 사용자 지정 구문 분석 또는 서식 지정을 수행 하려는 경우 사용자 지정 변환기를 구현할 수 있습니다. 다음은 몇 가지 예입니다.

DateTime(Offset).Parse및 사용DateTime(Offset).ToString

입력 또는 텍스트 표현의 형식을 확인할 수 없는 경우 DateTime DateTimeOffset DateTime(Offset).Parse 변환기의 읽기 논리에서 메서드를 사용할 수 있습니다. 이렇게 하면를 사용할 수 있습니다. DateTime DateTimeOffset Iso 8601 문자열 및 확장 된 iso 8601-1:2019 프로필을 준수 하지 않는 iso 8601 형식을 비롯 한 다양 한 텍스트 형식 구문 분석을 위한 광범위 한 기능을 제공 합니다. 이 방법은 serializer의 기본 구현을 사용 하는 것 보다 성능이 훨씬 낮습니다.

Serialize를 위해 DateTime(Offset).ToString 변환기 쓰기 논리에서 메서드를 사용할 수 있습니다. 이를 통해 DateTime DateTimeOffset 표준 날짜 및 시간 형식사용자 지정 날짜 및 시간 형식을사용 하 여 및 값을 작성할 수 있습니다. 이는 serializer의 기본 구현을 사용 하는 것 보다 성능이 훨씬 낮습니다.

using System;
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());
        }

        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"

참고

을 구현 하 JsonConverter<T>T 가 인 경우 DateTime typeToConvert 매개 변수는 항상 typeof(DateTime) 입니다. 매개 변수는 다형성 사례를 처리 하 고 제네릭을 사용 하 여 성능을 향상 시킬 때 유용 typeof(T) 합니다.

Utf8Parser및 사용Utf8Formatter

입력 DateTime 또는 DateTimeOffset 텍스트 표현이 "R", "l", "O" 또는 "G" 표준 날짜 및 시간 형식 문자열중 하나를 준수 하거나 이러한 형식 중 하나에 따라 쓰려면 변환기 논리에서 빠른 utf-8 기반 구문 분석 및 형식 지정 메서드를 사용할 수 있습니다. 이는 및을 사용 하는 것 보다 훨씬 빠릅니다 DateTime(Offset).Parse DateTime(Offset).ToString .

이 예제에서는 DateTime "R" 표준 형식에 따라 값을 serialize 및 deserialize 하는 사용자 지정 변환기를 보여 줍니다.

using System;
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://docs.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"

참고

"R" 표준 형식은 항상 29 자 길이입니다.

"L" (소문자 "L") 형식은 및 형식 에서만 지원 되므로 다른 표준 날짜 및 시간 형식 문자열 을 사용 하 여 문서화 되지 않습니다 Utf8Parser Utf8Formatter . 형식은 소문자 RFC 1123 ("R" 형식의 소문자 버전)입니다 (예: "목요일, 25 년 7 월 2019 06:36:07 gmt").

DateTime(Offset).ParseSerializer의 네이티브 구문 분석에 대 한 대체로를 사용 합니다.

일반적으로 입력 DateTime 또는 DateTimeOffset 데이터가 확장 된 ISO 8601-1:2019 프로필을 따르도록 하려면 serializer의 네이티브 구문 분석 논리를 사용할 수 있습니다. 경우에만 대체 메커니즘을 구현할 수도 있습니다. 이 예제에서는를 사용 하 여 텍스트 표현의 구문 분석에 실패 한 후 DateTime TryGetDateTime(DateTime) 변환기에서를 사용 하 여 데이터를 성공적으로 구문 분석 함을 보여 줍니다 Parse(String) .

using System;
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 epoch 날짜 형식 사용

다음 변환기는 표준 시간대 오프셋 (또는 같은 값)을 사용 하거나 사용 하지 않고 Unix epoch 형식을 처리 합니다 /Date(1590863400000-0700)/ /Date(1590863400000)/ .

sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
{
    static readonly DateTimeOffset s_epoch = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
    static readonly Regex s_regex = new Regex("^/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 TimeSpan(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 = FormattableString.Invariant($"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
        writer.WriteStringValue(formatted);
    }
}
sealed class UnixEpochDateTimeConverter : JsonConverter<DateTime>
{
    static readonly DateTime s_epoch = new DateTime(1970, 1, 1, 0, 0, 0);
    static readonly Regex s_regex = new Regex("^/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 = FormattableString.Invariant($"/Date({unixTime})/");
        writer.WriteStringValue(formatted);
    }
}

을 사용 하 여 작성 하는 경우 Utf8JsonWriter

를 사용 하 여 사용자 지정 DateTime 또는 텍스트 표현을 작성 하려는 경우 DateTimeOffset Utf8JsonWriter 사용자 지정 표현의 형식을,, 또는로 String ReadOnlySpan<Byte> ReadOnlySpan<Char> JsonEncodedText 지정한 다음 해당 Utf8JsonWriter.WriteStringValue 또는 메서드에 전달할 Utf8JsonWriter.WriteString 수 있습니다.

다음 예제에서는를 사용 하 여 사용자 지정 DateTime 형식을 만든 다음 메서드를 사용 하 여 작성 하는 방법을 보여 줍니다 ToString(String, IFormatProvider) WriteStringValue(String) .

using System;
using System.Globalization;
using System.IO;
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
// }

읽을 때 Utf8JsonReader

를 사용 하 여 사용자 지정 DateTime 또는 텍스트 표현을 읽으려면를 사용 하 여 DateTimeOffset Utf8JsonReader 현재 JSON 토큰의 값을 가져온 String GetString() 다음 사용자 지정 논리를 사용 하 여 값을 구문 분석할 수 있습니다.

다음 예제에서는를 사용 하 여 사용자 지정 DateTimeOffset 텍스트 표현을 검색 GetString() 한 다음를 사용 하 여 구문 분석 하는 방법을 보여 줍니다 ParseExact(String, String, IFormatProvider) .

using System;
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.object의 확장 된 ISO 8601-1:2019 프로필

날짜 및 시간 구성 요소

에 구현 된 확장 ISO 8601-1:2019 프로필은 System.Text.Json 날짜 및 시간 표현에 대해 다음과 같은 구성 요소를 정의 합니다. 이러한 구성 요소는 구문 분석 및 형식 지정 및 표현을 할 때 지원 되는 다양 한 수준의 세분성을 정의 하는 데 사용 됩니다 DateTime DateTimeOffset .

구성 요소 서식 Description
Year "yyyy" 0001-9999
"MM" 01-12
"dd" 월/연도를 기준으로 하는 01-28, 01-29, 01-30, 01-31
시간 "HH" 00-23
Minute "mm" 00-59
두 번째 "ss" 00-59
초 분수 "FFFFFFF" 최소 1 자리 숫자, 최대 16 자리
시간 오프셋 "K" "Z" 또는 "(' + '/'-') HH ': ' mm"
부분 시간 "HH ': ' mm ': ' ss [FFFFFFF]" UTC 오프셋 정보가 없는 시간
전체 날짜 "yyyy'-'mm'-'dd't'hh-'MM'-'dd" 달력 날짜
전체 시간 "' Partial time'K" 현지 시간과 UTC 사이의 시간 오프셋을 사용한 하루 또는 현지 시간 (UTC)
날짜 시간 "' 전체 날짜 ' ' ' ' 전체 시간 '" 달력 날짜 및 시간 (예: 2019-07-26T16:59:57-05:00)

구문 분석 지원

구문 분석에 대해 정의 되는 세분성 수준은 다음과 같습니다.

  1. ' 전체 날짜 '

    1. "yyyy'-'mm'-'dd't'hh-'MM'-'dd"
  2. "' 전체 날짜 ' ' ' ' ' 시간 ' ': ' ' Minute '"

    1. "yyyy'-'mm'-'dd't'hh-'MM'-' m ': ' MM '
  3. "' 전체 날짜 ' ' ' ' ' 부분 시간 '"

    1. "yyyy'-'mm'-'dd't'hh-'MM'-% Ddu: ' MM ': ' ss ' (정렬 가능한 (" s ") 서식 지정자)
    2. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ss '. ' FFFFFFF
  4. "' 전체 날짜 ' ' ' ' 시간 시간 ' ': ' ' Minute ' ' 시간 오프셋 '"

    1. "yyyy'-'mm'-'dd't'hh-'MM'-% n n e t ': ' mmZ '
    2. "yyyy'-'mm'-'dd't'hh-'MM'-% Ddn ': ' mm (' + '/'-') HH ': ' mm"
  5. ' 날짜 시간 '

    1. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ssZ '
    2. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ss '. ' FFFFFFFZ "
    3. "yyyy'-'mm'-'dd't'hh-'MM'-% n n e t ': ' mm ': ' ss (' + '/'-') HH ': ' mm '
    4. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ss '. ' FFFFFFF (' + '/'-') HH ': ' mm '

    이 세분성 수준은 interchanging 날짜 및 시간 정보에 사용 되는 ISO 8601의 널리 채택 된 프로필 인 RFC 3339을 준수 합니다. 그러나 System.object 구현에는 몇 가지 제한 사항이 있습니다.

    • RFC 3339는 최대 소수 자릿수 초의 자릿수를 지정 하지 않지만 소수 두 번째 섹션이 있는 경우 하나 이상의 숫자가 마침표 뒤에와 야 함을 지정 합니다. System.object의 구현은 다른 프로그래밍 언어 및 프레임 워크와의 상호 운용성을 지원 하기 위해 최대 16 자리 숫자를 허용 하지만 처음 7 개만 구문 분석 합니다. JsonException및 인스턴스를 읽을 때 소수 자릿수 초의 소수 자릿수가 16 개를 초과 하는 경우이 throw 됩니다 DateTime DateTimeOffset .
    • RFC 3339에서는 "T" 및 "Z" 문자를 각각 "t" 또는 "z"로 지정할 수 있지만 응용 프로그램에서 대/소문자 변형 으로만 지원을 제한할 수 있습니다. System.object의 구현에서는 "T" 및 "Z" 여야 합니다. JsonException및 인스턴스를 읽을 때 입력 페이로드에 "t" 또는 "z"가 포함 된 경우이 throw 됩니다 DateTime DateTimeOffset .
    • RFC 3339는 날짜 및 시간 섹션이 "T"로 구분 되도록 지정 하지만 응용 프로그램에서이를 공백 ("")으로 구분할 수 있도록 합니다. System.object를 사용 하려면 날짜 및 시간 섹션이 "T"로 구분 되어야 합니다. JsonException및 인스턴스를 읽을 때 입력 페이로드에 공백 ("")이 포함 된 경우이 throw 됩니다 DateTime DateTimeOffset .

초에 소수 자릿수가 있으면 숫자가 하나 이상 있어야 합니다. 2019-07-26T00:00:00. 허용 되지 않습니다. 최대 16 개의 소수 자릿수가 허용 되지만 처음 7 개만 구문 분석 됩니다. 그 외의 모든 항목은 0으로 간주 됩니다. 예를 들어 2019-07-26T00:00:00.1234567890 는 인 것 처럼 구문 분석 됩니다 2019-07-26T00:00:00.1234567 . 이는 DateTime 이 해상도로 제한 되는 구현과의 호환성을 유지 하기 위한 것입니다.

윤 초는 지원 되지 않습니다.

서식 지정 지원

서식 지정에 대해 정의 된 세분성 수준은 다음과 같습니다.

  1. "' 전체 날짜 ' ' ' ' ' 부분 시간 '"

    1. "yyyy'-'mm'-'dd't'hh-'MM'-% Ddu: ' MM ': ' ss ' (정렬 가능한 (" s ") 서식 지정자)

      DateTime오프셋 정보 없이 소수 자릿수 초 없이의 형식을 지정 하는 데 사용 됩니다.

    2. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ss '. ' FFFFFFF

      DateTime오프셋 정보 없이 소수 자릿수 초를 사용 하 여의 형식을 지정 하는 데 사용 됩니다.

  2. ' 날짜 시간 '

    1. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ssZ '

      소수 자릿수 초를 제외 하 고 UTC 오프셋을 사용 하 여의 형식을 지정 하는 데 사용 DateTime 됩니다.

    2. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ss '. ' FFFFFFFZ "

      소수 자릿수 초 및 UTC 오프셋을 사용 하 여의 형식을 지정 하는 데 사용 DateTime 됩니다.

    3. "yyyy'-'mm'-'dd't'hh-'MM'-% n n e t ': ' mm ': ' ss (' + '/'-') HH ': ' mm '

      소수 자릿수 초를 제외 하 고 로컬 오프셋을 사용 하 여의 형식을 지정 하는 데 사용 DateTime DateTimeOffset 됩니다.

    4. "yyyy'-'mm'-'dd't'hh-'MM'-% n이 (가): ' MM ': ' ss '. ' FFFFFFF (' + '/'-') HH ': ' mm '

      DateTime DateTimeOffset 현지 오프셋으로 또는 소수 자릿수 초를 사용 하 여의 형식을 지정 하는 데 사용 됩니다.

    이 세분성 수준은 RFC 3339을 준수 합니다.

또는 인스턴스의 라운드트립 형식 표현에 DateTime DateTimeOffset 소수 자릿수 초에 후행 0이 있으면 JsonSerializerUtf8JsonWriter 는 후행 0 없이 인스턴스 표현의 형식을 지정 합니다. 예를 들어 DateTime 라운드트립 형식 표현이 인 인스턴스는 2019-04-24T14:50:17.1010000Z 및에서로 형식이 지정 됩니다 2019-04-24T14:50:17.101Z JsonSerializer Utf8JsonWriter .

또는 인스턴스의 라운드트립 형식 표현에 DateTime DateTimeOffset 소수 자릿수 초의 0이 모두 있으면 JsonSerializerUtf8JsonWriter 는 소수 자릿수 초 없이 인스턴스 표현의 형식을 지정 합니다. 예를 들어 DateTime 라운드트립 형식 표현이 인 인스턴스는 2019-04-24T14:50:17.0000000+02:00 및에서로 형식이 지정 됩니다 2019-04-24T14:50:17+02:00 JsonSerializer Utf8JsonWriter .

소수점이 하 자릿수에서 0을 자르는 경우 라운드트립에 대 한 정보를 유지 하는 데 필요한 가장 작은 출력이 작성 됩니다.

최대 7 초의 소수 자릿수가 기록 됩니다. 이는 DateTime 이 해상도로 제한 되는 구현과 일치 합니다.