Skip to content

ADR 0007 half open intervals

Karthik P edited this page Oct 31, 2026 · 1 revision

ADR-0007: Half-open intervals

Every period is the half-open interval [start, end_exclusive), and last_day is derived from it.

Last reviewed: 31 Oct 2026

Status

Accepted on 31 Oct 2026. Decided by the research documents: design principle 7 of the research proposal. Built in 0.1.0.

Context

Periods are joined, split and compared constantly: a year is the union of its quarters, a dimension table covers a range of days, and range operations planned for 0.2 split a range across periods. With inclusive ends, every join needs a "plus one day" and every length needs a "plus one", which is where off-by-one errors come from. Finance users still think in last days ("the quarter ends on 3 February"), so that value must be available too.

Decision drivers

  • Adjacent periods should meet exactly: one period's end_exclusive is the next period's start.
  • Lengths should be a subtraction.
  • People should still see the last day without computing it.

Considered options

Option 1: Inclusive [start, end]

Pros:

  • Matches how filings and people state period ends.

Cons:

  • Joining and length need a correction of one day, which callers get wrong.

Option 2: Half-open [start, end_exclusive) only

Pros:

  • Clean arithmetic.

Cons:

  • Users who want the last day must subtract a day themselves.

Option 3: Half-open, plus a derived last_day (chosen)

Pros:

  • Arithmetic uses end_exclusive; display uses last_day.

Cons:

  • Two end fields can confuse a reader who does not know which is which. The Glossary and the spec define both.

Decision

Option 3. AGENTS.md design rule 5: every period exposes start and end_exclusive; last_day is derived; no API returns an inclusive end without also returning end_exclusive.

In 0.1.0 the Period value has start, end_exclusive and last_day, where last_day is end_exclusive minus one day (spec/api-v1.md). The dimension operation takes start and end_exclusive arguments, and its columns use *_start and *_last_day.

Consequences

Good:

  • Tiling is easy to state and test: every date in range belongs to exactly one period at every level, and children cover their parent exactly. The property tests check this (Testing-Strategy).

Bad:

  • The supported range must leave room for one day after the last period, because end_exclusive must be representable. That is one reason for the range in ADR-0018.
  • Dimension columns show *_last_day, not *_end_exclusive, so a BI user joining on ranges must add a day.

Links

Clone this wiki locally