using System; using System.Text.Json; using System.Text.Json.Serialization; namespace GB5Shared.DateConverter { /// /// GB5 standard DateTime converter. /// READ : ISO 8601 — "yyyy-MM-ddTHH:mm:ssZ" / "yyyy-MM-dd" /// Legacy — "/Date(milliseconds)/" or "/Date(milliseconds+offset)/" /// WRITE: "yyyy-MM-ddTHH:mm:ss.fffZ" (UTC ISO 8601) /// public class MicrosoftDateConverter : JsonConverter { public override DateTime Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { if (reader.TokenType == JsonTokenType.Null) return DateTime.MinValue; if (reader.TokenType == JsonTokenType.String) { var value = reader.GetString(); if (string.IsNullOrWhiteSpace(value)) return DateTime.MinValue; // Legacy Microsoft /Date(milliseconds)/ or /Date(milliseconds+offset)/ format if (value.StartsWith("/Date(", StringComparison.Ordinal) && value.EndsWith(")/", StringComparison.Ordinal)) { var inner = value.Substring(6, value.Length - 8); var signIdx = inner.IndexOfAny(new[] { '+', '-' }); var msStr = signIdx > 0 ? inner.Substring(0, signIdx) : inner; if (long.TryParse(msStr, out long ms)) return DateTimeOffset.FromUnixTimeMilliseconds(ms).UtcDateTime; return DateTime.MinValue; } if (DateTime.TryParse(value, null, System.Globalization.DateTimeStyles.RoundtripKind, out DateTime parsed)) return parsed.Kind == DateTimeKind.Unspecified ? DateTime.SpecifyKind(parsed, DateTimeKind.Utc) : parsed.ToUniversalTime(); return DateTime.MinValue; } return DateTime.MinValue; } public override void Write( Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options) { if (value == DateTime.MinValue || value == default) { writer.WriteNullValue(); return; } writer.WriteStringValue(value.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ss.fffZ")); } } }