System.Text.Json의 DateTime 및 DateTimeOffset 지원
System.Text.Json
라이브러리는 ISO 8601-1:2019 확장 프로필에 따라 DateTime 및 DateTimeOffset 값을 구문 분석하고 씁니다.
변환기JsonSerializer는 직렬화 및 역직렬화에 대한 사용자 지정 지원을 제공할 이(가) 있습니다. Utf8JsonReader 및 Utf8JsonWriter을(를) 사용하여 사용자 지정 지원을 구현할 수도 있습니다.
ISO 8601-1:2019 형식 지원
JsonSerializer, Utf8JsonReader, Utf8JsonWriter 및 JsonElement 형식은 ISO 8601-1:2019 형식의 확장된 프로필에 따라 DateTime 구문 분석 및 쓰기 DateTimeOffset 텍스트 표현을 작성합니다. 예들 들어 2019-07-26T16:59:57-05:00
입니다.
DateTime 및 DateTimeOffset 데이터는 JsonSerializer사용하여 serialize 할 수 있습니다.
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 및 DateTimeOffset 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
기본 옵션을 사용하면 입력 DateTime 및 DateTimeOffset 텍스트 표현이 확장된 ISO 8601-1:2019 프로필을 따라야 합니다. 프로필에 맞지 않는 표현을 역직렬화하려고 하면 JsonSerializer JsonException throw됩니다.
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 DateTime 및 DateTimeOffset 표현을 포함하여 JSON 페이로드의 콘텐츠에 대한 구조적 액세스를 제공합니다. 다음 예제에서는 온도 컬렉션에서 월요일의 평균 온도를 계산하는 방법을 보여 줍니다.
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 표현을 사용하여 페이로드가 지정된 평균 온도를 계산하려고 하면 JsonDocument 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()
하위 수준 Utf8JsonWriter DateTime 및 DateTimeOffset 데이터를 씁니다.
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 구문 분석 DateTime 및 DateTimeOffset 데이터.
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 비준수 형식을 읽으려고 하면 FormatException이(가) throw됩니다.
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 및 TimeOnly 속성 직렬화
.NET 7 이상에서 System.Text.Json
은 DateOnly 및 TimeOnly 형식을 직렬화 및 역직렬화할 수 있습니다. 다음 개체를 고려해 보세요.
sealed file record Appointment(
Guid Id,
string Description,
DateOnly Date,
TimeOnly StartTime,
TimeOnly EndTime);
다음 예제에서는 Appointment
개체를 직렬화하고 결과 JSON을 표시한 다음, Appointment
형식의 새 인스턴스로 다시 역직렬화합니다. 마지막으로 원래 인스턴스와 새로 역직렬화된 인스턴스가 같은지 비교된 후 결과가 콘솔에 기록됩니다.
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}
""");
위의 코드에서
Appointment
개체가 인스턴스화되고appointment
변수에 할당됩니다.appointment
인스턴스가 JsonSerializer.Serialize를 사용하여 JSON으로 직렬화됩니다.- 결과 JSON이 콘솔에 기록됩니다.
- JSON은 JsonSerializer.Deserialize를 사용하여
Appointment
형식의 새 인스턴스로 다시 역직렬화됩니다. - 원래 인스턴스와 새로 역직렬화된 인스턴스가 같은지 비교됩니다.
- 비교 결과는 콘솔에 기록됩니다.
DateTime 및 DateTimeOffset에 대한 사용자 지정 지원
JsonSerializer을(를) 사용하는 경우
직렬 변환기가 사용자 지정 구문 분석 또는 서식 지정을 수행하도록 하려면 사용자 지정 변환기를 구현할 수 있습니다. 다음은 몇 가지 예입니다.
DateTime(오프셋). 구문 분석 및 DateTime(오프셋). ToString
입력 DateTime 또는 DateTimeOffset 텍스트 표현의 형식을 확인할 수 없는 경우 변환기 읽기 논리에서 DateTime(Offset).Parse
메서드를 사용할 수 있습니다.
이 메서드를 사용하면 확장된 ISO 8601-1:2019 프로필을 준수하지 않는 ISO 8601 문자열 및 ISO 8601 형식을 포함하여 다양한 DateTime 및 DateTimeOffset 텍스트 형식을 구문 분석하기 위한 .NET의 광범위한 지원입니다.
이 방법은 serializer의 네이티브 구현을 사용하는 것보다 성능이 떨어집니다.
직렬화의 경우 변환기 쓰기 논리에서 DateTime(Offset).ToString
메서드를 사용할 수 있습니다.
이 메서드를 사용하면 표준 날짜 및 시간 형식 및 사용자 지정 날짜 및 시간 형식 중 사용하여 DateTime 및 DateTimeOffset 값을 작성할 수 있습니다.
또한 이 방법은 serializer의 네이티브 구현을 사용하는 것보다 성능이 떨어집니다.
using System.Diagnostics;
using System.Text.Json;
using System.Text.Json.Serialization;
using System.Text.RegularExpressions;
namespace DateTimeConverterExamples;
public class DateTimeConverterUsingDateTimeParse : JsonConverter<DateTime>
{
public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
Debug.Assert(typeToConvert == typeof(DateTime));
return DateTime.Parse(reader.GetString() ?? string.Empty);
}
public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
{
writer.WriteStringValue(value.ToString());
}
}
class Program
{
private static void ParseDateTimeWithDefaultOptions()
{
DateTime _ = JsonSerializer.Deserialize<DateTime>(@"""04-10-2008 6:30 AM""");
}
private static void FormatDateTimeWithDefaultOptions()
{
Console.WriteLine(JsonSerializer.Serialize(DateTime.Parse("04-10-2008 6:30 AM -4")));
}
private static void ProcessDateTimeWithCustomConverter()
{
JsonSerializerOptions options = new JsonSerializerOptions();
options.Converters.Add(new DateTimeConverterUsingDateTimeParse());
string testDateTimeStr = "04-10-2008 6:30 AM";
string testDateTimeJson = @"""" + testDateTimeStr + @"""";
DateTime resultDateTime = JsonSerializer.Deserialize<DateTime>(testDateTimeJson, options);
Console.WriteLine(resultDateTime);
string resultDateTimeJson = JsonSerializer.Serialize(DateTime.Parse(testDateTimeStr), options);
Console.WriteLine(Regex.Unescape(resultDateTimeJson));
}
static void Main(string[] args)
{
// Parsing non-compliant format as DateTime fails by default.
try
{
ParseDateTimeWithDefaultOptions();
}
catch (JsonException e)
{
Console.WriteLine(e.Message);
}
// Formatting with default options prints according to extended ISO 8601 profile.
FormatDateTimeWithDefaultOptions();
// Using converters gives you control over the serializers parsing and formatting.
ProcessDateTimeWithCustomConverter();
}
}
// The example displays output similar to the following:
// The JSON value could not be converted to System.DateTime. Path: $ | LineNumber: 0 | BytePositionInLine: 20.
// "2008-04-10T06:30:00-04:00"
// 4/10/2008 6:30:00 AM
// "4/10/2008 6:30:00 AM"
참고 항목
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
.보다 훨씬 빠릅니다.
다음 예제에서는 "R" 표준 형식에 따라 DateTime 값을 직렬화하고 역직렬화하는 사용자 지정 변환기를 보여 줍니다.
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"
참고 항목
"R" 표준 형식은 항상 29자 길이입니다.
"l"(소문자 "L") 형식은 Utf8Parser
및 Utf8Formatter
형식에서만 지원되므로 다른 표준 날짜 및 시간 형식 문자열과 함께 문서화되지 않습니다. 형식은 소문자 RFC 1123("R" 형식의 소문자 버전)입니다. 예: "thu, 25 jul 2019 06:36:07 gmt".
DateTime(오프셋)을 사용합니다. 대체로 구문 분석
일반적으로 입력 DateTime 또는 DateTimeOffset 데이터가 확장된 ISO 8601-1:2019 프로필을 준수해야 하는 경우 serializer의 네이티브 구문 분석 논리를 사용할 수 있습니다. 대체 메커니즘을 구현할 수도 있습니다. 다음 예제에서는 TryGetDateTime(DateTime)을(를) 사용하여 DateTime 텍스트 표현을 구문 분석하지 못한 후 변환기가 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"
Unix epoch 날짜 형식 사용
다음 변환기는 표준 시간대 오프셋(/Date(1590863400000-0700)/
또는 /Date(1590863400000)/
같은 값)을 사용하거나 사용하지 않고 Unix epoch 형식을 처리합니다.
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);
}
}
Utf8JsonWriter을(를) 사용하는 경우
Utf8JsonWriter을(를) 사용하여 사용자 지정 DateTime 또는 DateTimeOffset 텍스트 표현을 작성하려면 사용자 지정 표현을 String, ReadOnlySpan<Byte>
, ReadOnlySpan<Char>
또는 JsonEncodedText 서식을 지정한 다음 해당 Utf8JsonWriter.WriteStringValue 또는 Utf8JsonWriter.WriteString 메서드에 전달할 수 있습니다.
다음 예제에서는 ToString(String, IFormatProvider)을(를) 사용하여 사용자 지정 DateTime 형식을 만든 다음 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
// }
Utf8JsonReader을(를) 사용하는 경우
Utf8JsonReader을(를) 사용하여 사용자 지정 DateTime 또는 DateTimeOffset 텍스트 표현을 읽으려는 경우, GetString() 메서드를 사용하여 현재 JSON 토큰의 값을 String로써 가져오고 사용자 지정 논리를 사용하여 값을 구문 분석할 수 있습니다.
다음 예제에서는 GetString() 메서드를 사용하여 사용자 지정 DateTimeOffset 텍스트 표현을 검색한 다음 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
System.Text.Json의 확장 ISO 8601-1:2019 프로필
날짜 및 시간 구성 요소
System.Text.Json에서 구현된 확장 ISO 8601-1:2019 프로필은 날짜 및 시간 표현에 대해 다음 구성 요소를 정의합니다. 이러한 구성 요소는 DateTime 및 DateTimeOffset 표현을 구문 분석하고 서식을 지정할 때 지원되는 다양한 수준의 세분성을 정의하는 데 사용됩니다.
구성 요소 | 서식 | 설명 |
---|---|---|
Year | "yyyy" | 0001-9999 |
Month | "MM" | 01-12 |
요일 | "dd" | 월/연도 기준 01-28, 01-29, 01-30, 01-31 |
Hour | "HH" | 00-23 |
Minute | "mm" | 00-59 |
둘째 | "ss" | 00-59 |
두 번째 분수 | "FFFFFFF" | 최소 한 자리, 최대 16자리 숫자 |
시간 오프셋 | "K" | "Z" 또는 "('+'/'-')HH':'mm"입니다. |
부분 시간 | "HH':'mm':'ss[FFFFFFF]" | UTC 오프셋 정보가 없는 시간입니다. |
전체 날짜 | "yyyy'-'MM'-'dd" | 일정 날짜. |
풀 타임 | "'부분 시간'K" | 현지 시간과 UTC 사이의 시간 오프셋이 있는 일 또는 현지 시간의 UTC입니다. |
날짜 시간 | "'전체 날짜''T''전체 시간'" | 달력 날짜 및 시간(예: 2019-07-26T16:59:57-05:00). |
구문 분석 지원
구문 분석을 위해 다음과 같은 세분성 수준이 정의됩니다.
'전체 날짜'
- "yyyy'-'MM'-'dd"
"'전체 날짜''T''시'':''분'"
- "yyyy'-'MM'-'dd'T'HH':'mm"
"'전체 날짜''T''부분 시간'"
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss"(정렬 가능("s") 형식 지정자)
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF"
"'전체 날짜''T''시간 시'':''분''시간 오프셋'"
- "yyyy'-'MM'-'dd'T'HH':'mmZ"
- "yyyy'-'MM'-'dd'T'HH':'mm('+'/'-')HH':'mm"
'날짜 시간'
- "yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFZ"
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'-')HH':'mm"
- "yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF('+'/'-')HH':'mm"
이 수준의 세분성은 날짜 및 시간 정보를 교환하는 데 사용되는 ISO 8601의 널리 채택된 프로필인 RFC 3339를 준수합니다. 그러나
System.Text.Json
구현에는 몇 가지 제한 사항이 있습니다.- RFC 3339는 소수 자릿수 초 숫자의 최대 수를 지정하지 않지만 소수 자릿수 초 섹션이 있는 경우 적어도 한 자리가 마침표 뒤에 오도록 지정합니다.
System.Text.Json
구현은 최대 16자리(다른 프로그래밍 언어 및 프레임워크와의 interop 지원)를 허용하지만 처음 7자리만 구문 분석합니다.DateTime
및DateTimeOffset
인스턴스를 읽을 때 소수 자릿수가 16자리보다 많은 경우 JsonException이(가) throw됩니다. - RFC 3339는 "T" 및 "Z" 문자를 각각 "t" 또는 "z"로 허용하지만 애플리케이션은 대문자 변형으로만 지원을 제한할 수 있습니다.
System.Text.Json
을(를) 구현하려면 "T" 및 "Z"여야 합니다.DateTime
및DateTimeOffset
인스턴스를 읽을 때 입력 페이로드에 "t" 또는 "z"가 포함된 경우 JsonException이(가) throw됩니다. - RFC 3339는 날짜 및 시간 섹션을 "T"로 구분하도록 지정하지만 애플리케이션은 대신 공백(" ")으로 구분할 수 있습니다.
System.Text.Json
날짜 및 시간 섹션을 "T"로 구분해야 합니다. 입력 페이로드에DateTime
및DateTimeOffset
인스턴스를 읽을 때 공백(" ")이 포함된 경우 JsonException이(가) throw됩니다.
초 동안 소수 자릿수가 있는 경우 적어도 한 자리가 있어야 합니다. 2019-07-26T00:00:00.
은(는) 허용되지 않습니다.
최대 16개의 소수 자릿수가 허용되지만 처음 7개만 구문 분석됩니다. 그 이상의 모든 것은 0으로 간주됩니다.
예를 들어 2019-07-26T00:00:00.1234567890
이(가) 2019-07-26T00:00:00.1234567
인 것처럼 구문 분석됩니다.
이 방법은 이 해결로 제한되는 DateTime 구현과의 호환성을 유지합니다.
윤초는 지원되지 않습니다.
서식 지정 지원
다음 세분성 수준은 서식 지정에 대해 정의됩니다.
"'전체 날짜''T''부분 시간'"
"yyyy'-'MM'-'dd'T'HH':'mm':'ss"(정렬 가능("s") 형식 지정자)
소수 자릿수 초 및 오프셋 정보 없이 DateTime 서식을 지정하는 데 사용됩니다.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF"
오프셋 정보 없이 소수 자릿수 초로 DateTime 서식을 지정하는 데 사용됩니다.
'날짜 시간'
"yyyy'-'MM'-'dd'T'HH':'mm':'ssZ"
소수 자릿수 초 없이 UTC 오프셋을 사용하여 DateTime 서식을 지정하는 데 사용됩니다.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFFZ"
소수 자릿수 초 및 UTC 오프셋을 사용하여 DateTime 서식을 지정하는 데 사용됩니다.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss('+'/'-')HH':'mm"
소수 자릿수 초가 아닌 로컬 오프셋을 사용하여 DateTime 또는 DateTimeOffset 서식을 지정하는 데 사용됩니다.
"yyyy'-'MM'-'dd'T'HH':'mm':'ss'.'FFFFFFF('+'/'-')HH':'mm"
소수 자릿수 초 및 로컬 오프셋을 사용하여 DateTime 또는 DateTimeOffset 서식을 지정하는 데 사용됩니다.
이 세분성 수준은 RFC 3339를 준수합니다.
왕복 형식이 DateTime 또는 DateTimeOffset 인스턴스의 표현을 소수 자릿수 초의 후행 0이 있는 경우 JsonSerializer 및 Utf8JsonWriter 후행 0 없이 인스턴스의 표현 형식을 지정합니다.
예를 들어 왕복 형식 표현이 2019-04-24T14:50:17.1010000Z
인 DateTime 인스턴스는 JsonSerializer 및 Utf8JsonWriter에 의해 2019-04-24T14:50:17.101Z
(으)로써 형식이 지정됩니다.
왕복 형식이 DateTime 또는 DateTimeOffset 인스턴스의 표현을 소수 자릿수 초의 모든 0이 있는 경우 JsonSerializer 및 Utf8JsonWriter 소수 자릿수 초 없이 인스턴스의 표현 형식을 지정합니다.
예를 들어 왕복 형식 표현이 2019-04-24T14:50:17.0000000+02:00
인 DateTime 인스턴스는 JsonSerializer 및 Utf8JsonWriter에 의해 2019-04-24T14:50:17+02:00
(으)로써 형식이 지정됩니다.
소수 자릿수 초 숫자로 0을 잘리면 왕복에 대한 정보를 작성하는 데 필요한 가장 작은 출력을 사용할 수 있습니다.
최대 7개의 소수 자릿수 초 숫자가 기록됩니다. 이 최대값은 이 해상도로 제한되는 DateTime 구현과 일치합니다.
.NET