DateTime Formatting
Configure how DateTime, DateOnly, and TimeOnly values are stored and retrieved in DynamoDB.
Overview
FluentDynamoDb supports native serialization of .NET date and time types:
- DateTime - Full date and time with optional timezone
- DateTimeOffset - Date and time with explicit timezone offset
- DateOnly - Date without time component (.NET 6+)
- TimeOnly - Time without date component (.NET 6+)
All types are stored as strings in DynamoDB using ISO 8601 format by default, with support for custom format strings.
DateTime Serialization
Default Format (ISO 8601)
By default, DateTime values are serialized using ISO 8601 round-trip format:
[DynamoDbTable("Events")]
public partial class Event
{
[PartitionKey]
[DynamoDbAttribute("pk")]
public string Pk { get; set; } = string.Empty;
// Default ISO 8601 format: "2024-12-28T14:30:45.0000000Z"
[DynamoDbAttribute("createdAt")]
public DateTime CreatedAt { get; set; }
}
Custom Format
Use the Format property to specify a custom format string:
// Custom format: "12/28/2024 2:30:45 PM"
[DynamoDbAttribute("displayDate", Format = "MM/dd/yyyy h:mm:ss tt")]
public DateTime DisplayDate { get; set; }
DateOnly Serialization
DateOnly represents a date without a time component. Available in .NET 6+.
Default Format (ISO 8601)
[DynamoDbTable("Events")]
public partial class Event
{
[PartitionKey]
[DynamoDbAttribute("pk")]
public string Pk { get; set; } = string.Empty;
// Default ISO 8601 format: "2024-12-28"
[DynamoDbAttribute("eventDate")]
public DateOnly EventDate { get; set; }
}
Custom Format
// Custom format: "12/28/2024"
[DynamoDbAttribute("displayDate", Format = "MM/dd/yyyy")]
public DateOnly DisplayDate { get; set; }
// Long date format: "Saturday, December 28, 2024"
[DynamoDbAttribute("formattedDate", Format = "D")]
public DateOnly FormattedDate { get; set; }
DateOnly Format Specifiers
| Specifier | Description | Example Output |
|---|---|---|
o or O | ISO 8601 (default) | 2024-12-28 |
d | Short date | 12/28/2024 |
D | Long date | Saturday, December 28, 2024 |
yyyy-MM-dd | Custom | 2024-12-28 |
MM/dd/yyyy | Custom | 12/28/2024 |
dd-MMM-yyyy | Custom | 28-Dec-2024 |
DateOnly in Queries
var today = DateOnly.FromDateTime(DateTime.Today);
var events = await table.Events.Query()
.Where(x => x.TenantId == tenantId)
.WithFilter(x => x.EventDate == today)
.ToListAsync();
TimeOnly Serialization
TimeOnly represents a time without a date component. Available in .NET 6+.
Default Format (ISO 8601)
[DynamoDbTable("Schedules")]
public partial class Schedule
{
[PartitionKey]
[DynamoDbAttribute("pk")]
public string Pk { get; set; } = string.Empty;
// Default ISO 8601 format: "14:30:45.0000000"
[DynamoDbAttribute("startTime")]
public TimeOnly StartTime { get; set; }
}
Custom Format
// Custom format: "2:30 PM"
[DynamoDbAttribute("displayTime", Format = "h:mm tt")]
public TimeOnly DisplayTime { get; set; }
// 24-hour format: "14:30"
[DynamoDbAttribute("militaryTime", Format = "HH:mm")]
public TimeOnly MilitaryTime { get; set; }
TimeOnly Format Specifiers
| Specifier | Description | Example Output |
|---|---|---|
o or O | ISO 8601 (default) | 14:30:45.0000000 |
t | Short time | 2:30 PM |
T | Long time | 2:30:45 PM |
HH:mm | Custom 24-hour | 14:30 |
h:mm tt | Custom 12-hour | 2:30 PM |
HH:mm:ss | Custom with seconds | 14:30:45 |
TimeOnly in Queries
var businessStart = new TimeOnly(9, 0);
var businessEnd = new TimeOnly(17, 0);
var schedules = await table.Schedules.Query()
.Where(x => x.LocationId == locationId)
.WithFilter(x => x.StartTime.CompareTo(businessStart) >= 0
&& x.StartTime.CompareTo(businessEnd) <= 0)
.ToListAsync();
Collections of Date Types
DateOnly and TimeOnly work in collections:
[DynamoDbTable("Availability")]
public partial class Availability
{
[PartitionKey]
[DynamoDbAttribute("pk")]
public string Pk { get; set; } = string.Empty;
// List of available dates
[DynamoDbAttribute("availableDates")]
public List<DateOnly> AvailableDates { get; set; } = new();
// List of available time slots
[DynamoDbAttribute("timeSlots")]
public List<TimeOnly> TimeSlots { get; set; } = new();
}
Nullable Support
All date types support nullable values:
[DynamoDbAttribute("cancelledAt")]
public DateTime? CancelledAt { get; set; }
[DynamoDbAttribute("expiryDate")]
public DateOnly? ExpiryDate { get; set; }
[DynamoDbAttribute("endTime")]
public TimeOnly? EndTime { get; set; }
Update Expressions
DateOnly and TimeOnly work in update expressions:
await table.Events.Update(eventId)
.Set(x => new EventUpdateModel
{
EventDate = DateOnly.FromDateTime(DateTime.Today.AddDays(7)),
StartTime = new TimeOnly(10, 0)
})
.UpdateAsync();
Best Practices
Use DateOnly for Date-Only Data
// ✅ Good - DateOnly for birth dates, event dates, etc.
[DynamoDbAttribute("birthDate")]
public DateOnly BirthDate { get; set; }
// ⚠️ Avoid - DateTime when you only need the date
[DynamoDbAttribute("birthDate")]
public DateTime BirthDate { get; set; }
Use TimeOnly for Time-Only Data
// ✅ Good - TimeOnly for schedules, opening hours, etc.
[DynamoDbAttribute("openingTime")]
public TimeOnly OpeningTime { get; set; }
// ⚠️ Avoid - DateTime when you only need the time
[DynamoDbAttribute("openingTime")]
public DateTime OpeningTime { get; set; }
Consider Sort Key Compatibility
When using dates as sort keys, ensure the format sorts correctly:
// ✅ Good - ISO 8601 sorts lexicographically
[DynamoDbAttribute("eventDate")] // Default format: "2024-12-28"
public DateOnly EventDate { get; set; }
// ⚠️ Caution - MM/dd/yyyy doesn't sort correctly
[DynamoDbAttribute("eventDate", Format = "MM/dd/yyyy")] // "12/28/2024"
public DateOnly EventDate { get; set; }
See Also
- Entity Definition - Learn about entity attributes
- Lambda Expressions - Type-safe query expressions
- Updates - Update expressions