Skip to content

Commit debcbfb

Browse files
CopilotScarletKuro
andauthored
Add DateOnly and TimeOnly support (#2)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: ScarletKuro <19953225+ScarletKuro@users.noreply.github.com>
1 parent 9ec5c7f commit debcbfb

13 files changed

Lines changed: 601 additions & 31 deletions

AGENT.md

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ This document provides guidance for AI agents and developers working on the **Sc
1111
- Custom date/time format attributes (`JsonDateTimeConverterAttribute` for reflection, `JsonDateTimeFormatAttribute` for source generators)
1212
- Source generator-compatible format converters (`JsonDateTimeFormatConverter<T>`)
1313
- .NET 9+ contract customization resolver (`DateTimeConverterResolver`)
14-
- Support for `DateTime`, `DateTimeOffset`, and nullable variants
14+
- Support for `DateTime`, `DateTimeOffset`, `DateOnly`, `TimeOnly`, and nullable variants
1515
- Multi-target framework support (.NET 6, 7, 8, 9, 10)
1616

1717
## Repository Structure
@@ -31,7 +31,11 @@ Scarlet.System.Text.Json.DateTimeConverter/
3131
│ │ │ ├── DateTimeConverter.cs
3232
│ │ │ ├── DateTimeNullableConverter.cs
3333
│ │ │ ├── DateTimeOffsetConverter.cs
34-
│ │ │ └── DateTimeOffsetNullableConverter.cs
34+
│ │ │ ├── DateTimeOffsetNullableConverter.cs
35+
│ │ │ ├── DateOnlyConverter.cs
36+
│ │ │ ├── DateOnlyNullableConverter.cs
37+
│ │ │ ├── TimeOnlyConverter.cs
38+
│ │ │ └── TimeOnlyNullableConverter.cs
3539
│ │ ├── DateTimeConverterFactoryHelper.cs
3640
│ │ ├── DateTimeConverterResolver.cs # .NET 9+ contract customization
3741
│ │ ├── IJsonDateTimeFormat.cs
@@ -187,11 +191,15 @@ The project uses a standard GitHub workflow:
187191

188192
#### 1. Converters (Internal)
189193

190-
Four internal converter classes handle actual JSON serialization/deserialization:
194+
Eight internal converter classes handle actual JSON serialization/deserialization:
191195
- `DateTimeConverter` - for `DateTime`
192196
- `DateTimeNullableConverter` - for `DateTime?`
193197
- `DateTimeOffsetConverter` - for `DateTimeOffset`
194198
- `DateTimeOffsetNullableConverter` - for `DateTimeOffset?`
199+
- `DateOnlyConverter` - for `DateOnly`
200+
- `DateOnlyNullableConverter` - for `DateOnly?`
201+
- `TimeOnlyConverter` - for `TimeOnly`
202+
- `TimeOnlyNullableConverter` - for `TimeOnly?`
195203

196204
All use `CultureInfo.InvariantCulture` for consistent formatting.
197205

@@ -269,7 +277,7 @@ Tests verify four distinct usage patterns:
269277
4. **Source generator with resolver (old attribute)** - Uses `JsonDateTimeConverterAttribute` + `DateTimeConverterResolver` (.NET 9+, with SYSLIB1223 warnings for backward compatibility)
270278

271279
Each pattern is tested with:
272-
- Individual types (`DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?`)
280+
- Individual types (`DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?`, `DateOnly`, `DateOnly?`, `TimeOnly`, `TimeOnly?`)
273281
- Complete models
274282
- Null value handling
275283

README.md

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![Nuget](https://img.shields.io/nuget/dt/Scarlet.System.Text.Json.DateTimeConverter?color=ff4081&label=nuget%20downloads&logo=nuget)](https://www.nuget.org/packages/Scarlet.System.Text.Json.DateTimeConverter)
55
[![GitHub](https://img.shields.io/github/license/ScarletKuro/Scarlet.System.Text.Json.DateTimeConverter?color=594ae2&logo=github)](https://github.com/ScarletKuro/Scarlet.System.Text.Json.DateTimeConverter/blob/master/LICENSE)
66

7-
A flexible and powerful library for customizing `DateTime` and `DateTimeOffset` serialization in System.Text.Json, with full support for both reflection-based and source generator approaches.
7+
A flexible and powerful library for customizing `DateTime`, `DateTimeOffset`, `DateOnly`, and `TimeOnly` serialization in System.Text.Json, with full support for both reflection-based and source generator approaches.
88

99
## Table of Contents
1010

@@ -24,7 +24,7 @@ A flexible and powerful library for customizing `DateTime` and `DateTimeOffset`
2424

2525
## Overview
2626

27-
This package provides four ways to specify custom date formats for `DateTime`, `DateTimeOffset`, and their nullable counterparts when serializing and deserializing JSON using `System.Text.Json`:
27+
This package provides four ways to specify custom date formats for `DateTime`, `DateTimeOffset`, `DateOnly`, `TimeOnly`, and their nullable counterparts when serializing and deserializing JSON using `System.Text.Json`:
2828

2929
1. **`JsonDateTimeConverterAttribute`** - Simple attribute-based approach (reflection only, or .NET 9+ with resolver but produces warnings)
3030
2. **`JsonDateTimeFormatAttribute`** - Clean attribute for source generators with .NET 9+ resolver (no warnings)
@@ -102,19 +102,27 @@ public class Order
102102

103103
[JsonDateTimeConverter("yyyy-MM-ddTHH:mm:ss.fffZ")]
104104
public DateTimeOffset ShippedAt { get; set; }
105+
106+
[JsonDateTimeConverter("MM/dd/yyyy")]
107+
public DateOnly DeliveryDate { get; set; }
108+
109+
[JsonDateTimeConverter("HH:mm")]
110+
public TimeOnly DeliveryTime { get; set; }
105111
}
106112

107113
// Usage
108114
var order = new Order
109115
{
110116
OrderDate = new DateTime(2026, 1, 15),
111117
ProcessedDate = new DateTime(2026, 1, 15, 14, 30, 0),
112-
ShippedAt = DateTimeOffset.UtcNow
118+
ShippedAt = DateTimeOffset.UtcNow,
119+
DeliveryDate = new DateOnly(2026, 1, 20),
120+
DeliveryTime = new TimeOnly(10, 30)
113121
};
114122

115123
string json = JsonSerializer.Serialize(order);
116124
Console.WriteLine(json);
117-
// Output: {"OrderDate":"2026-01-15","ProcessedDate":"2026-01-15T14:30:00","ShippedAt":"2026-01-15T14:30:00.123Z"}
125+
// Output: {"OrderDate":"2026-01-15","ProcessedDate":"2026-01-15T14:30:00","ShippedAt":"2026-01-15T14:30:00.123Z","DeliveryDate":"01/20/2026","DeliveryTime":"10:30"}
118126
119127
var deserializedOrder = JsonSerializer.Deserialize<Order>(json);
120128
```
@@ -150,6 +158,12 @@ public class Order
150158

151159
[JsonConverter(typeof(JsonDateTimeFormatConverter<DateFormats.ISO8601>))]
152160
public DateTimeOffset ShippedAt { get; set; }
161+
162+
[JsonConverter(typeof(JsonDateTimeFormatConverter<DateFormats.DateOnlySlash>))]
163+
public DateOnly DeliveryDate { get; set; }
164+
165+
[JsonConverter(typeof(JsonDateTimeFormatConverter<DateFormats.TimeOnlyShort>))]
166+
public TimeOnly DeliveryTime { get; set; }
153167
}
154168

155169
// Define your custom date formats
@@ -169,6 +183,16 @@ public static class DateFormats
169183
{
170184
public static string Format => "yyyy-MM-ddTHH:mm:ss.fffZ";
171185
}
186+
187+
public class DateOnlySlash : IJsonDateTimeFormat
188+
{
189+
public static string Format => "MM/dd/yyyy";
190+
}
191+
192+
public class TimeOnlyShort : IJsonDateTimeFormat
193+
{
194+
public static string Format => "HH:mm";
195+
}
172196
}
173197

174198
// Create a JsonSerializerContext for source generation
@@ -181,7 +205,9 @@ var order = new Order
181205
{
182206
OrderDate = new DateTime(2026, 1, 15),
183207
ProcessedDate = new DateTime(2026, 1, 15, 14, 30, 0),
184-
ShippedAt = DateTimeOffset.UtcNow
208+
ShippedAt = DateTimeOffset.UtcNow,
209+
DeliveryDate = new DateOnly(2026, 1, 20),
210+
DeliveryTime = new TimeOnly(10, 30)
185211
};
186212

187213
string json = JsonSerializer.Serialize(order, typeof(Order), OrderJsonContext.Default);
@@ -225,6 +251,12 @@ public class Order
225251

226252
[JsonDateTimeFormat("yyyy-MM-ddTHH:mm:ss.fffZ")]
227253
public DateTimeOffset ShippedAt { get; set; }
254+
255+
[JsonDateTimeFormat("MM/dd/yyyy")]
256+
public DateOnly DeliveryDate { get; set; }
257+
258+
[JsonDateTimeFormat("HH:mm")]
259+
public TimeOnly DeliveryTime { get; set; }
228260
}
229261

230262
[JsonSerializable(typeof(Order))]
@@ -427,6 +459,10 @@ This matches standard `System.Text.Json` behavior.
427459
- `DateTime?`
428460
- `DateTimeOffset`
429461
- `DateTimeOffset?`
462+
- `DateOnly`
463+
- `DateOnly?`
464+
- `TimeOnly`
465+
- `TimeOnly?`
430466

431467
All types support any valid [.NET date and time format string](https://learn.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings).
432468

0 commit comments

Comments
 (0)