Osy#betaRun it on Osyrin: osyrin.com

Reference / Function

Constructing a DateTime, DateOnly, or TimeOnly

DateTime.New(y, m, d[, h, mi, s]) → DateTime · DateOnly.New(y, m, d) → DateOnly · TimeOnly.New(h, m[, s]) → TimeOnly

Build a temporal value from its components. DateTime.New takes a date, optionally with a time (defaulting to midnight); DateOnly.New takes a calendar date with no time; TimeOnly.New takes a time of day with no date. For a value coming from a string, Parse is the sibling. All run in the browser.

stable2 examples compiled by CIfunctiondatetimedatetime

Summary#

⚠ There is no DateOnly.Today (nor a TimeOnly.Now) — DateOnly/TimeOnly have no member that reads the clock. For today's date as a DateOnly, take the date part off the current instant instead: DateOnly.FromDateTime(DateTime.UtcNow) (see Current time (DateTime.UtcNow, DurableClock.Now) for DateTime.UtcNow/DurableClock.UtcNow).

When you have the components rather than a string, these build the value directly. DateTime.New(y, m, d) makes a date at midnight, and DateTime.New(y, m, d, h, mi, s) includes the time. DateOnly.New(y, m, d) makes a bare calendar date, and TimeOnly.New(h, m) / TimeOnly.New(h, m, s) makes a bare time of day. DateOnly.FromDateTime(dt) / TimeOnly.FromDateTime(dt) split a DateTime into its date or time half — the way to get "today"/"now" as a bare DateOnly/TimeOnly, since neither has its own clock read.

Signature#

DateTime.New(<int> year, <int> month, <int> day)                          -> DateTime  // 00:00:00
DateTime.New(<int> year, <int> month, <int> day, <int> hour, <int> minute, <int> second) -> DateTime
DateTime.New(<int> year, <int> month, <int> day, <int> hour, <int> minute, <int> second, <DateTimeKind> kind) -> DateTime
DateTime.SpecifyKind(<DateTime> value, <DateTimeKind> kind)                               -> DateTime
DateOnly.New(<int> year, <int> month, <int> day)                          -> DateOnly
TimeOnly.New(<int> hour, <int> minute)                                    -> TimeOnly   // seconds = 0
TimeOnly.New(<int> hour, <int> minute, <int> second)                      -> TimeOnly
DateOnly.FromDateTime(<DateTime> dt)                                      -> DateOnly   // no DateOnly.Today — this is "today"
TimeOnly.FromDateTime(<DateTime> dt)                                      -> TimeOnly   // no TimeOnly.Now — this is "now"

Description#

DateTime.New builds a DateTime from whole components. With three arguments the time is midnight; the six-argument form sets the time explicitly. The result is a UTC instant, consistent with the rest of the date surface (Current time (DateTime.UtcNow, DurableClock.Now) explains why a DateTime here is always UTC).

DateTimeKind — accepted, and what it means here#

new DateTime(y, m, d, h, mi, s, DateTimeKind.Utc) is what a C# author writes for an instant that is unambiguously UTC, and it compiles. So does DateTime.SpecifyKind(value, DateTimeKind.Utc).

They change nothing, and that is the point: every DateTime in Osy# is already a UTC instant (Current time (DateTime.UtcNow, DurableClock.Now)), so Utc and Unspecified both name the instant the components describe. The overload exists so the idiom you already know means what it says instead of failing to compile.

⛔ DateTimeKind.Local is refused, by name. It asks for the machine's own time zone — a fact about where the code ran, not about the value, so it would mean one thing on the server and another in the browser. For a wall clock in a particular place use TimeZoneInfo: TimeZoneInfo.ConvertTimeFromUtc(instant, zone) reads one, and zone.GetUtcOffset(instant) its offset.

DateOnly.New and TimeOnly.New build the two "half" values — a date with no time, and a time with no date (TimeSpan, DateOnly, TimeOnly). TimeOnly.New defaults the seconds to 0 when you pass only hours and minutes.

Constructing vs parsing. Use New when you have the numeric components; use DateTime.Parse(s) (and DateOnly.Parse / TimeOnly.Parse) when you have a string — for example an ISO timestamp from an API. The parsing side lives with the current-time surface, Current time (DateTime.UtcNow, DurableClock.Now).

These are pure, so they run in the browser with no round trip (Reading a date — Year, Month, Day, Hour, Minute, Second, DayOfWeek, DayOfYear, Date reads the components back off the value you build).

Examples#

DateTime MonthStart(int year, int month) {
  return DateTime.New(year, month, 1);      // day 1, midnight
}
[Test]
void Datetime_construct() {
  // three args → midnight
  var midnight = DateTime.New(2024, 3, 15);
  Assert.Equal(15, midnight.Day);
  Assert.Equal(0, midnight.Hour);
  Assert.Equal(1, MonthStart(2024, 3).Day);

  // six args → explicit time
  var full = DateTime.New(2024, 3, 15, 13, 45, 30);
  Assert.Equal(13, full.Hour);
  Assert.Equal(30, full.Second);

  // seven args → the same instant, said explicitly. `Unspecified` says it too; `Local` is refused at compile.
  var kinded = DateTime.New(2024, 3, 15, 13, 45, 30, DateTimeKind.Utc);
  Assert.Equal(full, kinded);
  Assert.Equal(full, DateTime.New(2024, 3, 15, 13, 45, 30, DateTimeKind.Unspecified));
  Assert.Equal(full, DateTime.SpecifyKind(full, DateTimeKind.Utc));

  // the half values
  Assert.Equal(29, DateOnly.New(2024, 2, 29).Day);    // a valid leap day
  Assert.Equal(45, TimeOnly.New(13, 45).Minute);
  Assert.Equal(0, TimeOnly.New(13, 45).Second);        // seconds default to 0
  Assert.Equal(30, TimeOnly.New(13, 45, 30).Second);

  // "today" as a bare DateOnly — there is no `DateOnly.Today`; split it off the current instant instead
  var today = DateOnly.FromDateTime(DateTime.UtcNow);
  Assert.Equal(DateTime.UtcNow.Year, today.Year);
}

See also#

Related

Current time (DateTime.UtcNow, DurableClock.Now)

Read the current instant. `DateTime.UtcNow` (and the platform-idiomatic `DurableClock.Now`/…) return the current time…

Reading a date — Year, Month, Day, Hour, Minute, Second, DayOfWeek, DayOfYear, Date

Read a component off a DateTime — its year, month, day, hour, minute, second — or its day of the week (a DayOfWeek, as…

DateTime

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…

TimeSpan, DateOnly, TimeOnly

A duration, a bare date, and a bare time of day. Subtracting two DateTimes gives a TimeSpan; adding one back gives a…