using System; using System.Text.Json; using System.Text.Json.Serialization; namespace GB5Shared.DateConverter { /// /// GB5 standard DateOnly converter. /// READ : "yyyy-MM-dd" ISO date string only /// WRITE: "yyyy-MM-dd" /// /// Epoch /Date(N)/ format is NO LONGER accepted — removed by design. /// public sealed class DateOnlyJsonConverter : JsonConverter { public override DateOnly Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) return DateOnly.MinValue; if (reader.TokenType == JsonTokenType.String) { var raw = reader.GetString(); if (string.IsNullOrWhiteSpace(raw)) return DateOnly.MinValue; if (DateOnly.TryParseExact(raw, "yyyy-MM-dd", System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.None, out var date)) return date; // Accept full ISO datetime string — extract date portion only if (DateTime.TryParse(raw, System.Globalization.CultureInfo.InvariantCulture, System.Globalization.DateTimeStyles.RoundtripKind, out var dt)) return DateOnly.FromDateTime(dt); throw new JsonException( $"Invalid date value '{raw}'. Expected ISO format 'yyyy-MM-dd'."); } throw new JsonException( $"Unexpected token {reader.TokenType} for DateOnly; expected a string."); } public override void Write( Utf8JsonWriter writer, DateOnly value, JsonSerializerOptions options) { if (value == DateOnly.MinValue) { writer.WriteNullValue(); return; } writer.WriteStringValue(value.ToString("yyyy-MM-dd")); } } public sealed class NullableDateOnlyJsonConverter : JsonConverter { private static readonly DateOnlyJsonConverter _inner = new(); public override DateOnly? Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) return null; var val = _inner.Read(ref reader, typeof(DateOnly), options); return val == DateOnly.MinValue ? null : val; } public override void Write( Utf8JsonWriter writer, DateOnly? value, JsonSerializerOptions options) { if (!value.HasValue) { writer.WriteNullValue(); return; } _inner.Write(writer, value.Value, options); } } }