Skip to main content

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​

SpecifierDescriptionExample Output
o or OISO 8601 (default)2024-12-28
dShort date12/28/2024
DLong dateSaturday, December 28, 2024
yyyy-MM-ddCustom2024-12-28
MM/dd/yyyyCustom12/28/2024
dd-MMM-yyyyCustom28-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​

SpecifierDescriptionExample Output
o or OISO 8601 (default)14:30:45.0000000
tShort time2:30 PM
TLong time2:30:45 PM
HH:mmCustom 24-hour14:30
h:mm ttCustom 12-hour2:30 PM
HH:mm:ssCustom with seconds14: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​