Osy#the first language built for agents
Agents firstAgentic appsWorkflowsDurable Execution — built inSecurityTestingThe editorThe UI modelOne program

Reference / Types

DateTime

DateTime — a wall-clock date and time, exact to 100 nanoseconds

A date and time. It is a wall-clock value, not an instant on a timeline, so it is never shifted by anybody's timezone. Reading its parts and doing calendar arithmetic on it work identically in the browser and on the server; reading the current time is a server operation.

stable1 example compiled by CItypesdatetimestdlib

Summary#

DateTime is a date and a time of day — 2024-03-15T13:45:30 — held exactly, to 100 nanoseconds. You read its parts (d.Year, d.DayOfWeek), do calendar arithmetic on it (d.AddMonths(1)), and construct or parse one (new DateTime(2024, 3, 15), DateTime.Parse(s)).

Signature#

new DateTime(<int> year, <int> month, <int> day)
new DateTime(<int> year, <int> month, <int> day, <int> hour, <int> minute, <int> second)
DateTime.Parse(<string> s) -> DateTime

DateTime.MinValue -> DateTime         // the earliest representable value
DateTime.MaxValue -> DateTime         // the latest representable value

d.Year · d.Month · d.Day · d.Hour · d.Minute · d.Second · d.DayOfWeek · d.Date
d.AddDays(n) · d.AddMonths(n) · d.AddYears(n) · d.AddHours(n) · d.AddMinutes(n)

Description#

What are DateTime.MinValue and MaxValue?#

DateTime.MinValue and DateTime.MaxValue are the earliest and latest values a DateTime can hold. They are ordinary values, so they compare and sort like any other date — which is what makes them useful as a starting point for a running comparison (var earliest = DateTime.MaxValue; then keep the smaller of each candidate).

They are not a "no date" marker. A DateTime? says "no date" precisely and reads as null; a sentinel says it by convention and every reader has to know the convention. Prefer the nullable type — a MinValue that leaks into a UI renders as a real date in the year 1, and a MinValue that reaches a comparison silently sorts first.

It is a wall-clock value, not an instant#

2024-03-15T13:45:30 means that reading on a clock face. It is not "a moment in time as seen from a timezone", and nothing in the platform will shift it by one. A date you store is the date you get back — the same one, in the same digits, whether it is read on a server in Frankfurt or in a browser in São Paulo.

That is worth stating plainly because most date libraries do the opposite, and quietly.

Calendar arithmetic clamps the day#

AddMonths and AddYears move along the calendar, and clamp the day to the target month rather than overflowing it:

new DateTime(2024, 1, 31).AddMonths(1)     // 2024-02-29  — a leap year
new DateTime(2025, 1, 31).AddMonths(1)     // 2025-02-28
new DateTime(2024, 2, 29).AddYears(1)      // 2025-02-28

None of those becomes March 2nd. If you want exactly thirty days later, say AddDays(30).

AddDays, AddHours and AddMinutes take a fractional amount and round it to the nearest millisecond, so AddDays(0.5) is exactly twelve hours.

DayOfWeek counts from Sunday#

d.DayOfWeek is 0 for Sunday through 6 for Saturday.

Reading the current time#

DurableClock.Now, DurableClock.UtcNow and DurableClock.Today give the current instant, and they run on the client — reading "now" costs no round trip. That is safe here for a reason worth knowing: a DateTime is a UTC instant, not a wall-clock reading, so the browser and the server name the same value (9am in Frankfurt is 5pm in Tokyo). Test pinning still applies, and a durable flow that pauses and resumes still sees the instant it saw before, because the engine resumes from a saved point rather than re-running the body from the top.

DateTime.Now and DateTime.UtcNow are the same instant, because there is no local-time DateTime here for them to differ by. Local is a question about a person, not a property of the platform — so when you want a wall clock, name the zone: DateTime.UtcNow.InZone(Zone.Of("Europe/Stockholm")).

Everything else about a date — its parts, its arithmetic, parsing and formatting it — runs wherever you are, with no round trip.

Examples#

bool IsOverdue(DateTime due) {
  return due < DurableClock.UtcNow;
}

DateTime NextBillingDate(DateTime start) {
  return start.AddMonths(1);
}
// NextBillingDate(new DateTime(2024, 1, 31))  ->  2024-02-29

See also#

  • decimal — the other exact value type, and the same reasoning behind it
  • format specifiers — rendering a date or a number to a string
  • execution side — why the clock is a server operation and the arithmetic is not

Related

decimal

Exact base-10 arithmetic, for money and anything else where a fraction of a cent matters. It behaves identically…

execution side

Where a function runs. Osy# infers it from the body: a function that reads data runs on the server, a function that…

format specifiers

Formats a number to a string with a .NET format specifier — F2 for two decimal places, N0 for a grouped whole number, C…