/**
 * time/range — the library's one range, its two spellings, and one
 * conversion per boundary a range crosses.
 *
 * Pattern: one internal shape, converted at every edge by a named function —
 *          never inline. Inside the library a range is HALF-OPEN `[from, to)`;
 *          the places a range crosses do not share that edge (the time design,
 *          `docs/design/time/README.md` § 3.3), so each crossing is a function
 *          here and its inverse.
 * Role:    L0 leaf (the time layer's one owner). Imports `instant.ts` and
 *          `duration.ts`. Asked by `tools/declare.ts` ·
 *          `parsesUnderSpelling` (an `iso-range` argument is
 *          {@link splitRange} under `'..'` and the strict profile). No other
 *          file splits or joins a range.
 * Emits:   N/A.
 *
 * ## The boundaries
 *
 * | Boundary | Its edge | Into it from `[from, to)` | Back |
 * |----------|----------|---------------------------|------|
 * | a result's `DeclaredPeriod.queried` / `held` | inclusive at both ends | not converted — the tool declares it | {@link fromInclusive} with the tool's step (`granularity`, else 1 ms) |
 * | a tool argument bound | declared on every `bounds`/`object` end (TQ18); only the sugar defaults inclusive | {@link boundInto} | {@link boundFrom} |
 * | a look-back argument | `[until − L, until]` | {@link lookbackRange} | {@link lookbackOf} |
 * | an ask answer / an ISO 8601 interval | `from/to`, half-open | identity: {@link spellRange} | identity: {@link parseRange} |
 * | an inclusive interval clause (SQL `BETWEEN`, a chart brush) | inclusive at both ends | {@link toInclusive} | {@link fromInclusive} |
 *
 * `coverage/period.ts` · `periodVerdict` stays inclusive and is NOT routed
 * through here: it compares the two inclusive spans a result declared.
 *
 * A derived bound keeps the offset its source was written in, spelled in the
 * strict profile; a bound that is not derived is kept as written.
 *
 * @example
 * ```ts
 * parseRange('2026-10-09T08:00:00-07:00/2026-10-09T08:41:00-07:00');
 * // { from: '2026-10-09T08:00:00-07:00', to: '2026-10-09T08:41:00-07:00' }
 * toInclusive({ from: '2026-10-09T08:00:00-07:00', to: '2026-10-09T08:41:00-07:00' }, 60_000);
 * // { from: '2026-10-09T08:00:00-07:00', to: '2026-10-09T08:40:00-07:00' } — "through 08:40"
 * ```
 */
import { type DurationText } from './duration.js';
import { type InstantProfile, type InstantText, type ParsedInstant } from './instant.js';
/**
 * The library's INTERNAL range: half-open `[from, to)`, `from` before `to`.
 * NOT the same reading as `DeclaredPeriod.queried`, whose bounds are
 * inclusive — every boundary converts (the module table).
 */
export interface TimeRange {
    readonly from: InstantText;
    readonly to: InstantText;
}
/** Two instants with inclusive ends, `from` not after `to` — a declared period's span, an SQL `BETWEEN`. */
export interface InclusiveSpan {
    readonly from: InstantText;
    readonly to: InstantText;
}
/** How two bounds are joined in one string: an ISO 8601 interval (`/`) or a tool's joined argument (`..`). */
export type RangeJoiner = '/' | '..';
/** Whether a tool's bound includes the instant it names. */
export type Edge = 'inclusive' | 'exclusive';
/**
 * The two bounds of a joined range string — exactly one `joiner`, each half an
 * instant under `profile` — or `undefined`. The ORDER is not checked: a format
 * check, for a declaration that only promises a spelling.
 */
export declare function splitRange(value: unknown, joiner: RangeJoiner, profile: InstantProfile): readonly [ParsedInstant, ParsedInstant] | undefined;
/**
 * A joined string read as a {@link TimeRange} — strict instants, `from`
 * before `to` — or `undefined`. The bounds are kept as written.
 */
export declare function parseRange(value: unknown, joiner?: RangeJoiner): TimeRange | undefined;
/** Whether `value` is a well-formed {@link TimeRange}: strict instants, `from` before `to`, no other key. */
export declare function isTimeRange(value: unknown): value is TimeRange;
/** The range spelled as one string: `from<joiner>to`, bounds as written. Throws on a range that is not well formed. */
export declare function spellRange(range: TimeRange, joiner?: RangeJoiner): string;
/** The step a tool's `granularity` names (under `units`), else 1 ms — the § 3.3 rule. */
export declare function stepMsOf(granularity: DurationText | undefined, units: string): number;
/**
 * An inclusive span read back as half-open: `[from, to + step)`. The step is
 * the source's smallest step (a tool's `granularity`, else 1 ms). The span is
 * read in the LENIENT profile — a result declares it.
 */
export declare function fromInclusive(span: InclusiveSpan, stepMs?: number): TimeRange;
/**
 * A half-open range written with inclusive ends: `[from, to − step]` — the
 * last instant inside the range at the reader's precision. Refused when the
 * range is narrower than one step (it holds no instant at that precision).
 */
export declare function toInclusive(range: TimeRange, stepMs?: number): InclusiveSpan;
/**
 * A half-open range's end as a tool's `to` bound: `exclusive` → as is;
 * `inclusive` → the last instant inside at the argument's precision
 * (`to − step`).
 */
export declare function boundInto(to: InstantText, edge: Edge, stepMs: number): InstantText;
/** The inverse of {@link boundInto}: a tool's `to` bound as a half-open range's end. */
export declare function boundFrom(to: InstantText, edge: Edge, stepMs: number): InstantText;
/**
 * A look-back `duration` evaluated at `until` — `[until − L, until]`, both
 * ends inside — as a half-open range `[until − L, until + 1 ms)`.
 */
export declare function lookbackRange(until: InstantText, duration: DurationText, units: string): TimeRange;
/**
 * The inverse of {@link lookbackRange}: the `until` and the smallest exact
 * look-back spelling a half-open range is, or `undefined` when its length is
 * no whole duration in `units`.
 */
export declare function lookbackOf(range: TimeRange, units: string): {
    readonly until: InstantText;
    readonly duration: DurationText;
} | undefined;
/**
 * How far a half-open range `[from, to)` REACHES, in milliseconds: from its
 * first instant to its last (`to − 1 ms − from`) — the length a tool's
 * `maxRange` is held against (an inclusive ceiling: a range is over it only
 * when its last instant lies further than `maxRange` after its first). The one
 * owner of that length, so a range is judged by the instants it holds, never by
 * how it was spelled: the look-back row `[until − L, until]` ({@link lookbackRange},
 * half-open `[until − L, until + 1 ms)`) reaches `L`, exactly as the same instants
 * written as bounds do — a look-back exactly `maxRange` long is one the tool reads
 * at once, and one more step (`L + 1 min`) is not.
 *
 * @example
 * ```ts
 * reachMs(Date.parse('2026-10-08T15:40:00Z'), Date.parse('2026-10-09T15:40:00.001Z')); // 86_400_000 — 'last 24h'
 * reachMs(Date.parse('2026-10-08T00:00:00Z'), Date.parse('2026-10-09T00:00:00Z'));     // 86_399_999 — one day
 * ```
 */
export declare function reachMs(fromMs: number, toMs: number): number;
/** Whether `outer` holds every instant of `inner` (half-open). */
export declare function covers(outer: TimeRange, inner: TimeRange): boolean;
/** Whether two ranges hold the same instants (their spellings and offsets aside). */
export declare function sameRange(a: TimeRange, b: TimeRange): boolean;
/** Whether `a` and `b` share at least one instant (half-open: touching ends do not overlap). */
export declare function overlaps(a: TimeRange, b: TimeRange): boolean;
/**
 * The range widened to whole steps — `from` down, `to` up, never inward —
 * with `rounded` saying whether anything moved. Steps are counted from the
 * epoch in UTC: right for seconds, minutes and hours; a calendar day or week
 * in a zone is `zone.ts`'s question, not this one.
 */
export declare function roundOutward(range: TimeRange, stepMs: number): {
    readonly range: TimeRange;
    readonly rounded: boolean;
};
//# sourceMappingURL=range.d.ts.map