Skip to main content

@cosyte/dates

Classes​

AmbiguousLocalTimeError​

A local time was placed in a named zone where it does not exist, or exists twice.

Both cases are resolved by REFUSING rather than by picking. A daylight-saving transition is exactly where a silent choice shifts a clinical timeline by an hour, so the caller is told and decides.

Extends​

  • Error

Constructors​

Constructor​

new AmbiguousLocalTimeError(message): AmbiguousLocalTimeError

Parameters​
message​

string

Returns​

AmbiguousLocalTimeError

Overrides​

Error.constructor


DatePartsError​

A conversion was asked for a value that validation reports invalid.

issues is the SAME array validateParts() returns for that value, so a caller that catches this never has to validate again to learn what was wrong, and a conversion never returns a coerced or clamped stand-in.

Extends​

  • Error

Constructors​

Constructor​

new DatePartsError(issues): DatePartsError

Parameters​
issues​

readonly ValidationIssue[]

Returns​

DatePartsError

Overrides​

Error.constructor

Properties​

issues​

readonly issues: readonly ValidationIssue[]


MissingZoneError​

An absolute instant was asked for, and nothing said which zone the local time is in.

This package never falls back to the host timezone, to UTC, or to any other default, because a fallback turns an unknown into a plausible wrong answer.

Extends​

  • Error

Constructors​

Constructor​

new MissingZoneError(message): MissingZoneError

Parameters​
message​

string

Returns​

MissingZoneError

Overrides​

Error.constructor


PrecisionError​

The value does not carry enough precision for what was asked, and supplying the missing components would mean inventing them.

Extends​

  • Error

Constructors​

Constructor​

new PrecisionError(message, precision): PrecisionError

Parameters​
message​

string

precision​

string

Returns​

PrecisionError

Overrides​

Error.constructor

Properties​

precision​

readonly precision: string

The precision the value actually has.

Interfaces​

DateParts​

The date-parts value every @cosyte/* parser hands back, and the only shape this package accepts.

Two rules make it a contract rather than a bag of numbers.

  1. CONTIGUITY. Components are present from the most significant downward with no gaps. { year, month } is legal; { year, day } is not.
  2. PRECISION IS WHAT IS PRESENT. The least significant present component IS the precision of the value. Nothing here adds a component that was not supplied, and an absent offsetMinutes means the offset is UNKNOWN, which is not the same as UTC and not the same as the host zone.

month is SPEC-NATIVE 1-12, not JavaScript's 0-11.

Properties​

day?​

readonly optional day?: number

1-31, and a day that exists in the given month of the given year.

fraction?​

readonly optional fraction?: number

Sub-second precision as a fraction of one second: 0 <= fraction < 1.

hour?​

readonly optional hour?: number

0-23.

minute?​

readonly optional minute?: number

0-59.

month?​

readonly optional month?: number

1-12, spec-native. January is 1.

offsetMinutes?​

readonly optional offsetMinutes?: number

Signed minutes from UTC, -1439 to 1439. ABSENT means the offset is unknown. It never means zero, and it is never filled in from the host zone.

second?​

readonly optional second?: number

0-59. Leap seconds are not representable.

year?​

readonly optional year?: number

Four digits, 1000-9999. Required. Two-digit years are never interpreted.


InvalidPartsResult​

An invalid value, with every fault found rather than only the first.

Properties​

issues​

readonly issues: readonly ValidationIssue[]

valid​

readonly valid: false


ValidationIssue​

One thing wrong with one component, named.

Properties​

code​

readonly code: IssueCode

component​

readonly component: PartName | "value"

The component at fault, or 'value' when the argument itself is wrong.

message​

readonly message: string

Human-readable, names the component and the range or calendar rule broken.


ValidPartsResult​

A validated value, carrying only the recognised components that were present.

Properties​

parts​

readonly parts: DateParts

precision​

readonly precision: "year" | "month" | "day" | "hour" | "minute" | "second" | "fraction"

valid​

readonly valid: true


ZoneOptions​

How to place a value that carries no offset of its own onto the timeline.

A value that DOES carry offsetMinutes is never re-zoned: its own offset is what the sender said, and overriding it here would move the instant.

Properties​

offsetMinutes?​

readonly optional offsetMinutes?: number

A fixed offset in signed minutes from UTC, -1439 to 1439.

timeZone?​

readonly optional timeZone?: string

An IANA time zone identifier, for example 'America/New_York'.

Type Aliases​

IssueCode​

IssueCode = "not-a-parts-object" | "missing-component" | "unreadable" | "not-a-number" | "not-finite" | "not-an-integer" | "out-of-range" | "year-not-four-digits" | "finer-than-nanosecond" | "offset-without-time-of-day" | "no-such-calendar-date"

What a diagnostic says went wrong.


PartName​

PartName = Precision | "offsetMinutes"

Every component name the contract defines.


Precision​

Precision = typeof PRECISION_LADDER[number]

The least significant component present in a value IS its precision.


TemporalValue​

TemporalValue = Temporal.PlainYearMonth | Temporal.PlainDate | Temporal.PlainDateTime | Temporal.ZonedDateTime

The narrowest Temporal type that carries everything a value states, and nothing more.


ValidationResult​

ValidationResult = ValidPartsResult | InvalidPartsResult

Variables​

PRECISION_LADDER​

const PRECISION_LADDER: readonly ["year", "month", "day", "hour", "minute", "second", "fraction"]

The precision ladder, most significant first.


Temporal​

Temporal: any

The Temporal implementation this package converts into, re-exported so a consumer works with the same objects rather than installing a second copy. Two Temporal implementations do not share instanceof.

Functions​

assertValidParts()​

assertValidParts(value): DateParts

Validate and return the recognised components, or throw DatePartsError carrying the same diagnostics validateParts would have reported.

Parameters​

value​

unknown

Returns​

DateParts


isValidParts()​

isValidParts(value): value is DateParts

A type guard over validateParts, for callers that want a boolean.

Parameters​

value​

unknown

Returns​

value is DateParts


precisionOf()​

precisionOf(value): "year" | "month" | "day" | "hour" | "minute" | "second" | "fraction"

The precision of a value: its least significant present component.

Throws DatePartsError for a value that does not satisfy the contract, because an invalid value has no precision to report.

Parameters​

value​

unknown

Returns​

"year" | "month" | "day" | "hour" | "minute" | "second" | "fraction"


toInstant()​

toInstant(value, options?): Instant

The absolute instant a value denotes, in a stated zone.

Same requirements as toZonedDateTime: a time of day, and a zone that something states. Nothing is defaulted.

Parameters​

value​

unknown

options?​

ZoneOptions

Returns​

Instant


toISO()​

toISO(value): string

Render a value as an ISO 8601 string AT ITS OWN PRECISION.

A year-only value renders 1988; a month-only value renders 1988-05. No component the value did not state is ever added, so nothing here turns a year of birth into the first of January.

The result is a pure function of the parts. It does not read the host clock or the host time zone, so it is identical under every TZ.

Parameters​

value​

unknown

Returns​

string

Throws​

if the value does not satisfy the contract.


toTemporal()​

toTemporal(value): any

Convert to the narrowest Temporal type that carries everything the value states, and nothing it does not.

precision of the valueresult
monthTemporal.PlainYearMonth
dayTemporal.PlainDate, with no time of day and no zone
hour and finer, no offsetTemporal.PlainDateTime, with no zone
hour and finer, with offsetMinutesTemporal.ZonedDateTime at that exact offset

A year-only value has no Temporal counterpart and raises PrecisionError rather than acquiring a month. Use toISO for those, and precisionOf to branch.

Components below the value's own precision are zero in the Temporal object, because Temporal has no partial type below PlainYearMonth. The value's real precision is still available from precisionOf; it is not lost, it just cannot be carried by the returned object.

Parameters​

value​

unknown

Returns​

any

Throws​

if the value does not satisfy the contract.

Throws​

for a year-only value.


toZonedDateTime()​

toZonedDateTime(value, options?): ZonedDateTime

Place a value on the timeline in a stated zone.

Requires a time of day. A day-precision value is a calendar date, and turning one into a zoned instant means choosing midnight, which is a component the value does not carry. Use toTemporal for those.

Requires a zone. If the value carries offsetMinutes that offset is used and PRESERVED EXACTLY, never normalised to UTC or to the host zone, and options are not consulted. Otherwise options.timeZone or options.offsetMinutes must say which zone the local time is in.

A local time that a named zone skips or repeats across a daylight-saving transition raises AmbiguousLocalTimeError rather than resolving to one of the two candidates, because a silent pick shifts the value by an hour.

Parameters​

value​

unknown

options?​

ZoneOptions

Returns​

ZonedDateTime

Throws​

if the value does not satisfy the contract.

Throws​

if the value states no time of day.

Throws​

if nothing says which zone applies.

Throws​

at a daylight-saving transition.


validateParts()​

validateParts(value): ValidationResult

Check a value against the date-parts contract.

Every fault is reported, not only the first, and every diagnostic names the component at fault together with the range or calendar rule it broke. Nothing is coerced, clamped or inferred: a value that does not satisfy the contract comes back invalid rather than corrected.

This function never throws, for any argument at all. Hostile input (null, a string, a JavaScript Date, NaN, Infinity, a non-integer component, a component that throws when it is read) is reported, not raised.

Components are looked up by name, so an object carrying them on its prototype (a class instance with accessors, which is a shape a parser may well hand over) is read the same way a plain object literal is.

Parameters​

value​

unknown

Returns​

ValidationResult