Summary#
DateOnly is a calendar date with no time component; TimeOnly is a time of day with no date — the same
split as C#. Both are first-class scalars you can declare, pass, and store on an entity (alongside DateTime and
TimeSpan).
Signature#
new DateOnly(year, month, day) // a calendar date
new TimeOnly(hour, minute) // a time of day
new TimeOnly(hour, minute, second)
DateOnly.FromDateTime(dt) / TimeOnly.FromDateTime(dt) // the date / time part of a DateTime
d.ToDateTime(t) // …and back: a date + a time of day = a DateTime
DateOnly.Parse(s) / TimeOnly.Parse(s) // from a string (throws on a bad value)
d.Year / d.Month / d.Day / d.DayOfWeek // DateOnly parts
d.DayNumber // days since 0001-01-01 — subtract two to count days between
t.Hour / t.Minute / t.Second // TimeOnly partsDescription#
Construct with the C# spelling — new DateOnly(2026, 3, 15) / new TimeOnly(9, 30) (a three-argument TimeOnly
adds seconds). FromDateTime splits a DateTime into its date or time half. Parse reads one from a string
(invariant format; it throws on an unparseable value). Read the parts with the same member names as C#
(.Year/.Month/.Day; .Hour/.Minute/.Second), and format with .ToString("fmt").
How many days between two dates?#
Subtract their DayNumbers — C#'s own spelling, and the only one there is:
entity Item { [Required, MaxLength(60)] string Name; [Required] DateOnly AddedOn; }
int DaysIn(DateOnly addedOn) {
return DateOnly.FromDateTime(DateTime.UtcNow).DayNumber - addedOn.DayNumber;
}DayNumber is the count of days since 0001-01-01, so the difference between two of them is the number of days
between the two dates. Two dates cannot be subtracted directly — a DateOnly carries no time, so there is no
duration between them, and C# has no such operator either. When you do want a duration with hours and minutes in
it, subtract two DateTimes instead: that gives a TimeSpan.
⚠ A date read out of a DateTime counts the same as the date itself: DayNumber is taken from the calendar day,
so a value stamped at 23:59 and one stamped at 00:01 the same morning answer the same number.
Both are computed in memory and stored as ordinary columns (a DateOnly as a SQL date, a TimeOnly as a
time).
Examples#
DateOnly Christmas() {
return new DateOnly(2026, 12, 25);
}
int MeetingHour() {
var t = new TimeOnly(9, 30, 0);
return t.Hour; // 9
}
DateOnly DatePart(DateTime dt) {
return DateOnly.FromDateTime(dt); // the calendar date, time dropped
}
int MinuteOf(DateTime dt) {
return TimeOnly.FromDateTime(dt).Minute;
}A DateOnly / TimeOnly is also an ordinary entity column — no conversion to write, and no DateTime to fall
back on. This example is COMPILED by the docs gate, so the claim is checked rather than asserted:
entity Appointment {
DateOnly Day; // a SQL `date` — no time of day to get wrong
TimeOnly StartsAt; // a SQL `time` — no date attached
}
DateOnly DayOf(Appointment a) { return a.Day; } // reads back as itself, not as a DateTime
TimeOnly StartOf(Appointment a) { return a.StartsAt; }See also#
- entity members — every type an entity member may hold, in one table
- TimeSpan (durations) — durations, and
DateTime/TimeSpanarithmetic - Current time (DateTime.UtcNow, DurableClock.Now) — reading the clock (
DateTime.UtcNow), parsing, and formatting