| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758 |
- using System.Text.Json;
- using System.Text.Json.Serialization;
- namespace Web.Api.Common;
- /// <summary>
- /// DB 의 모든 DateTime 컬럼은 UTC 로 저장된다(Domain Entity 가 일관되게 DateTime.UtcNow 사용).
- /// SQL Server datetime2 컬럼은 timezone 정보가 없어 EF Core 가 Kind = Unspecified 로 materialize 한다.
- /// System.Text.Json 의 기본 동작은 Unspecified DateTime 을 Z/offset 없이 출력해서, 클라이언트 JS 가
- /// 로컬 시간으로 오해 → 9시간(KST 오프셋) 차이 발생. 이 converter 가 Z 마커를 강제해서 문제를 해결.
- /// </summary>
- public sealed class UtcDateTimeConverter : JsonConverter<DateTime>
- {
- public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- var dt = reader.GetDateTime();
- return dt.Kind == DateTimeKind.Utc ? dt : DateTime.SpecifyKind(dt, DateTimeKind.Utc);
- }
- public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
- {
- var utc = value.Kind switch
- {
- DateTimeKind.Utc => value,
- DateTimeKind.Local => value.ToUniversalTime(),
- _ => DateTime.SpecifyKind(value, DateTimeKind.Utc)
- };
- writer.WriteStringValue(utc.ToString("yyyy-MM-ddTHH:mm:ss.fffZ"));
- }
- }
- public sealed class UtcNullableDateTimeConverter : JsonConverter<DateTime?>
- {
- private static readonly UtcDateTimeConverter Inner = new();
- public override DateTime? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
- {
- if (reader.TokenType == JsonTokenType.Null)
- {
- return null;
- }
- return Inner.Read(ref reader, typeof(DateTime), options);
- }
- public override void Write(Utf8JsonWriter writer, DateTime? value, JsonSerializerOptions options)
- {
- if (value is null)
- {
- writer.WriteNullValue();
- return;
- }
- Inner.Write(writer, value.Value, options);
- }
- }
|