How do I add or subtract time from a date in EK9?

← Date, Time, and Duration · Ref: Q540

Use the + and - operators with Duration literals. EK9 supports both simple and compound assignment forms.

BASIC ARITHMETIC

  nextWeek <- 2024-01-15 + P7D
  lastMonth <- 2024-06-15 - P1M
  meetingEnd <- 2024-06-15T10:00:00Z + PT1H30M

COMPOUND ASSIGNMENT

  appointment <- 2024-03-01
  appointment += P2W
  appointment -= P3D

INCREMENT AND DECREMENT

  today <- Date().today()
  today++
  today--

For Date, ++ adds one day and -- subtracts one day.
For DateTime, ++ and -- also add/subtract one day.

THE DURATION SUMMING PITFALL

In languages with true calendar month arithmetic (Java, Python), month addition is NOT associative:

  Java: Jan 31 + 1 month = Feb 28 (clamped to month end)
        Feb 28 + 1 month = Mar 28
  But:  Jan 31 + 2 months = Mar 31 (different!)

Sequential single-month additions clamp at each step, losing information.

EK9 uses a predictable 30-day approximation for months:

  P1M = 30 days. P2M = 60 days. Always.
  date + P1M + P1M = date + 60 days
  date + P2M = date + 60 days (same result!)

Month arithmetic IS associative in EK9. The trade-off: P1M is always 30 days, not the actual number of days in any specific month.

For calendar-precise month logic, construct new dates from components (see Q550 for the deep dive).

MILLISECOND ARITHMETIC

You can also add Millisecond values:

  precise <- 2024-06-15T10:00:00Z + 5000ms

See Q32 for Duration literals. See Q539 for date subtraction. See Q550 for calendar edge cases and the full duration summing deep dive. See Q556 for Time wrapping.

Example

defines module qa.add.subtract.time

  defines program
    AddSubtractTimeDemo()
      stdout <- Stdout()

      // Basic date + duration
      start <- 2024-01-15
      nextWeek <- start + P7D
      lastMonth <- start - P1M
      stdout.println(`Start: ${start}`)
      stdout.println(`+ P7D: ${nextWeek}`)
      stdout.println(`- P1M: ${lastMonth}`)

      // Complex duration
      future <- start + P1Y6M10D
      stdout.println(`+ P1Y6M10D: ${future}`)

      // Compound assignment
      appointment <- 2024-03-01
      appointment += P2W
      stdout.println(`+ P2W: ${appointment}`)
      appointment -= P3D
      stdout.println(`- P3D: ${appointment}`)

      // Increment and decrement (one day)
      mutableDate <- 2024-06-15
      mutableDate++
      stdout.println(`After ++: ${mutableDate}`)
      mutableDate--
      stdout.println(`After --: ${mutableDate}`)

      // DateTime arithmetic
      meeting <- 2024-06-15T10:00:00Z
      meetingEnd <- meeting + PT1H30M
      stdout.println(`Meeting end: ${meetingEnd}`)

      // Duration summing: EK9 is associative
      // P1M = 30 days always, so P1M + P1M = P2M = 60 days
      base <- 2024-01-15
      sequential <- base + P1M + P1M
      combined <- base + P2M
      stdout.println(`Sequential P1M + P1M: ${sequential}`)
      stdout.println(`Combined P2M: ${combined}`)
      require sequential == combined

      // Millisecond arithmetic
      precise <- 2024-06-15T10:00:00Z + 5000ms
      stdout.println(`+ 5000ms: ${precise}`)

      // Time arithmetic (wraps at 24h - see Q556)
      evening <- 22:00
      lateNight <- evening + PT3H
      stdout.println(`22:00 + PT3H: ${lateNight}`)

Common mistakes

E50060 — Date has no plusDays() method. EK9 uses the + operator with Duration literals (P7D for 7 days) for date arithmetic. See ek9 -h E50060 for details.

Incorrect:

nextWeek <- start.plusDays(7)

Correct:

nextWeek <- start + P7D
Other ways to ask this
  • How does date arithmetic work with Duration?
  • How do I add days or months to a date?
  • What is the duration summing pitfall?

Coming from another language?

Java: date.plusDays(7), date.plusMonths(1) calendar-safe but non-associative (Jan 31 + 1 month + 1 month differs from Jan 31 + 2 months). Python: timedelta(days=7) for days only, relativedelta for months (same non-associativity). JavaScript: manual setDate/setMonth (notoriously broken). Go: t.AddDate(0, 1, 0) calendar-safe but non-associative. EK9: date + P7D, P1M = 30 days always, associative arithmetic. Trade-off: predictable vs calendar-precise.

Keywords: timezone, duration, migrate, arithmetic, add, increment, month, minus, plus, associative, pitfall, calculate, calendar, date, time, decrement, subtract, summing