diff --git a/src/NATS.Client.JetStream/Models/StreamSource.cs b/src/NATS.Client.JetStream/Models/StreamSource.cs index 0529bcb47..e35d138dd 100644 --- a/src/NATS.Client.JetStream/Models/StreamSource.cs +++ b/src/NATS.Client.JetStream/Models/StreamSource.cs @@ -35,6 +35,7 @@ public record StreamSource /// [System.Text.Json.Serialization.JsonPropertyName("opt_start_time")] [System.Text.Json.Serialization.JsonIgnore(Condition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingDefault)] + [System.Text.Json.Serialization.JsonConverter(typeof(NatsJSJsonDateTimeOffsetConverter))] public DateTimeOffset OptStartTime { get; set; } /// diff --git a/src/NATS.Client.JetStream/NatsJSJsonSerializer.cs b/src/NATS.Client.JetStream/NatsJSJsonSerializer.cs index 375be743f..a2662a540 100644 --- a/src/NATS.Client.JetStream/NatsJSJsonSerializer.cs +++ b/src/NATS.Client.JetStream/NatsJSJsonSerializer.cs @@ -1,3 +1,4 @@ +using System.Buffers.Text; using System.Text.Json; using System.Text.Json.Serialization; using NATS.Client.Core; @@ -393,3 +394,24 @@ public override void Write(Utf8JsonWriter writer, TimeSpan? value, JsonSerialize } } } + +internal class NatsJSJsonDateTimeOffsetConverter : JsonConverter +{ + public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + return default; + } + + return reader.GetDateTimeOffset(); + } + + public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options) + { + // Write the date time in the format e.g. "2024-01-01T00:00:00Z" + // instead of the default DateTimeOffset format e.g. "2024-01-01T00:00:00+00:00" + // which is confusing the server. + writer.WriteStringValue(value.UtcDateTime); + } +} diff --git a/tests/NATS.Client.JetStream.Tests/TimeSpanJsonTests.cs b/tests/NATS.Client.JetStream.Tests/TimeSpanJsonTests.cs index 08a927a2f..8402a936c 100644 --- a/tests/NATS.Client.JetStream.Tests/TimeSpanJsonTests.cs +++ b/tests/NATS.Client.JetStream.Tests/TimeSpanJsonTests.cs @@ -1,5 +1,6 @@ using System.Buffers; using System.Text; +using System.Text.Json; using NATS.Client.JetStream.Internal; using NATS.Client.JetStream.Models; @@ -7,6 +8,20 @@ namespace NATS.Client.JetStream.Tests; public class TimeSpanJsonTests { + [Fact] + public void NatsJSJsonDateTimeOffsetConverter_serialize_UTC_offset_as_Z() + { + var streamSource = new StreamSource + { + Name = "events", + OptStartTime = DateTimeOffset.Parse("2024-01-01T00:00:00+00:00"), + }; + + var json = JsonSerializer.Serialize(streamSource, NatsJSJsonSerializerContext.Default.StreamSource); + + Assert.Equal("""{"name":"events","opt_start_time":"2024-01-01T00:00:00Z"}""", json); + } + [Theory] [InlineData("00:00:00.001", "\"ack_wait\":1000000\\b")] [InlineData("00:00:01.000", "\"ack_wait\":1000000000\\b")]