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

Reference / Function

Date arithmetic — AddDays, AddMonths, AddYears, AddHours, AddMinutes

d.AddDays(n) / AddHours(n) / AddMinutes(n) / AddMonths(n) / AddYears(n) → DateTime

Move a DateTime forward or back. AddDays/AddHours/AddMinutes take a fractional amount and are exact. AddMonths and AddYears are CALENDAR-aware and CLAMP the day: Jan 31 + 1 month is Feb 29 in a leap year and Feb 28 otherwise, never March 2nd. A negative amount goes backward. They run wherever the expression does — in the browser, on the server, and **inside a query the database executes**, where each lowers to a real SQL interval.

stable2 examples compiled by CIfunctiondatetimedatestdlib

Summary#

These shift a DateTime by an amount. AddDays, AddHours and AddMinutes take a fractional amount and are exact time arithmetic. AddMonths and AddYears are calendar-aware: they land on the same day-of-month where it exists and clamp to the last day of the month where it does not. A negative amount moves backward.

Signature#

d.AddDays(<number> n)    -> DateTime     // n may be fractional (0.5 = 12 hours)
d.AddHours(<number> n)   -> DateTime
d.AddMinutes(<number> n) -> DateTime
d.AddMonths(<int> n)     -> DateTime     // calendar month, day CLAMPED
d.AddYears(<int> n)      -> DateTime     // calendar year, Feb 29 CLAMPED

Description#

They work INSIDE a query — the database does the arithmetic#

AddDays and its siblings are not client-only helpers. Written inside a Where, each lowers to a real SQL interval, so the comparison happens in the database and only the matching rows come back:

// the whole due-list, computed by the database — one filtered read
live var due = Plant.Where(p => p.LastWateredAt.AddDays(p.WaterEveryDays) <= DateTime.UtcNow).ToList();

The alternative is a full table read. Plant.ToList() followed by an in-memory Where fetches every row on every page load and filters them in the browser — correct on ten rows, and a table scan on ten thousand. If the predicate can be written over the entity, write it there: see Where / Single / Count.

AddDays / AddHours / AddMinutes are exact time arithmetic#

They add a fixed length of time and roll components over: AddHours(11) on 13:45 crosses midnight into the next day, AddMinutes(90) adds an hour and a half. The amount may be fractionalAddDays(0.5) is twelve hours, AddMinutes(0.5) is thirty seconds — and it may be negative to go backward.

AddMonths / AddYears CLAMP the day — the rule that surprises people#

A calendar month is not a fixed number of days, so "one month after January 31st" has no exact answer. AddMonths and AddYears resolve it by clamping the day to the last valid day of the target month:

CallResultWhy
Jan 31 . AddMonths(1)Feb 29 (2024)Feb has no 31st; clamp to the last day — and 2024 is a leap year
Jan 31 . AddMonths(13)Feb 28 (2025)thirteen months on, into a non-leap year
Feb 29 . AddYears(1)Feb 28the target year has no Feb 29

It never spills over into the next month — you will not get "March 2nd" from adding a month to January 31st. The time of day is preserved across all of these.

The member syntax d.AddMonths(1) is the everyday spelling; the compiler knows these as Date.AddDays, Date.AddHours, Date.AddMinutes, Date.AddMonths and Date.AddYears, and they can also be written in that call form (Date.AddMonths(d, 1)).

Every one is a pure function of the value, so it runs in the browser with no round trip (execution side). To add a duration instead of a fixed unit, add a TimeSpan (durations).

Examples#

DateTime DueNextMonth(DateTime placed) {
  return placed.AddMonths(1);
}
[Test]
void Date_arithmetic() {
  var d = DateTime.New(2024, 3, 15, 13, 45, 30);

  // exact, fractional, and reversible
  Assert.Equal(16, d.AddDays(1).Day);
  Assert.Equal(1, d.AddDays(0.5).Hour);       // +12h → 01:45 next day
  Assert.Equal(16, d.AddHours(11).Day);       // crosses midnight
  Assert.Equal(0, d.AddHours(11).Hour);

  // AddMonths / AddYears clamp the day to the month end
  var jan31 = DateTime.New(2024, 1, 31);
  Assert.Equal(2, jan31.AddMonths(1).Month);
  Assert.Equal(29, jan31.AddMonths(1).Day);   // Feb 29 in a leap year, NOT March 2nd
  Assert.Equal(28, jan31.AddMonths(13).Day);  // Feb 28 in 2025

  var feb29 = DateTime.New(2024, 2, 29);
  Assert.Equal(28, feb29.AddYears(1).Day);    // 2025 has no Feb 29
}

See also#

Related

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

Read a component off a DateTime — its year, month, day, hour, minute, second — or its day of the week (Sunday is 0), or…

Current time (DateTime.UtcNow, DurableClock.Now)

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

TimeSpan (durations)

`TimeSpan` is the duration type — a length of time, as in C#. Build one with the `TimeSpan.FromX` factories or `new…

execution side

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