/** * Every date rule in EDF, in one place. * * Layer 2. Sole owner of: the `dd.mm.yy` header startdate, the `hh.mm.ss` clock, the * `dd-MMM-yyyy` subfield date used by the patient birthdate and the recording-identification * `Startdate`, the 1985-2084 two-digit-year rule, the literal `'yy'` post-2084 escape, and the * resolution between the two dates a file can carry. * * A JavaScript `Date` is never constructed. EDF stores local time at the patient with no * timezone, so a `Date` would silently apply the reader's zone — worst exactly at DST * boundaries — and `lib: ["ES2022"]` gives us no reason to reach for one anyway. Month lengths * and leap years are arithmetic, and `'31.02.99'` must never quietly become 3 March. * * Separators and stray spaces are tolerated (`' 2. 8.51'` is in the EDF FAQ). A tolerated * deviation is reported through `conformant` on the parse result rather than as a diagnostic: * the vocabulary in `diagnostics/codes.ts` has no code for a date that parsed but was written * oddly, and inventing one is not this module's call. */ import type { DiagnosticSink } from '../diagnostics/collector.js'; import type { EdfCalendarDate, EdfClockTime, EdfStartTime } from '../types.js'; export declare function isLeapYear(year: number): boolean; export declare function daysInMonth(year: number, month: number): number; /** * Whether a date names a day that exists. Real files carry 31 April and 29 February in common * years, and a `Date` would roll both forward into a neighbouring month rather than reject them — * which is the whole reason edfcore validates the digits itself. */ export declare function isValidCalendarDate(date: EdfCalendarDate): boolean; export declare function calendarDatesEqual(a: EdfCalendarDate, b: EdfCalendarDate): boolean; /** `'1951-08-02'`. Used in diagnostic messages and by `formatStartTimeNaive`. */ export declare function formatCalendarDate(date: EdfCalendarDate): string; /** `'09:00:00'`. */ export declare function formatClockTime(clock: EdfClockTime): string; /** * The EDF 1985-2084 window, applied to a two-digit year. Not a heuristic and not adjustable: the * specification fixes the pivot, so a file written in 1984 or after 2084 cannot state its year in * this field at all — which is what the EDF+ `Startdate` subfield exists to carry instead. */ export declare function resolveTwoDigitYear(twoDigitYear: number): number; /** * `parsed` — a full date. `yearEscape` — the year position held the literal `'yy'`, so only the * recording-identification `Startdate` knows the year. `unparseable` — nothing usable. */ export type HeaderStartDateStatus = 'parsed' | 'yearEscape' | 'unparseable'; /** * The outcome of reading the 8-byte startdate, with the partial results kept rather than * discarded. A field can yield a day and month but no year — that is what the `yy` escape means * — and the EDF+ `Startdate` supplies the rest, so throwing the halves away would lose the date. */ export interface HeaderStartDateParse { readonly status: HeaderStartDateStatus; /** Present only when `status === 'parsed'`. */ readonly date: EdfCalendarDate | undefined; /** Present when the day and month parsed, including under the year escape. */ readonly day: number | undefined; readonly month: number | undefined; /** The 1985-2084 rule was applied to a two-digit year. */ readonly clippedYear: boolean; /** The field is exactly `dd.mm.yy`. False means it parsed only because we tolerate. */ readonly conformant: boolean; readonly raw: string; } /** * The `dd.mm.yy` startdate at offset 168. * * A four-digit year is accepted where it fits (`'2.8.1951'`), because a writer that spells the * year out is unambiguous and the two-digit rule would be a downgrade. Three digits are * corruption, not a convention, and are refused. */ export declare function parseHeaderStartDate(raw: string): HeaderStartDateParse; /** * The outcome of reading the 8-byte starttime. Simpler than its date counterpart because there is * no escape and no second field to rescue a partial answer: the clock either reads or it does * not, and `conformant` separates "read because it was well formed" from "read because we * tolerate". */ export interface HeaderStartTimeParse { readonly clock: EdfClockTime | undefined; /** The field is exactly `hh.mm.ss`. */ readonly conformant: boolean; readonly raw: string; } /** The `hh.mm.ss` starttime at offset 176. Whole seconds only — EDF has no finer field. */ export declare function parseHeaderStartTime(raw: string): HeaderStartTimeParse; /** * A date read from an identification subfield — `dd-MMM-yyyy`, four-digit year, English month * name. A different grammar from the header's `dd.mm.yy` and a different result type, because * this one has no two-digit window to apply and therefore nothing to clip. */ export interface SubfieldDateParse { readonly date: EdfCalendarDate | undefined; /** The text is exactly `dd-MMM-yyyy` with an uppercase English month, and names a real day. */ readonly conformant: boolean; } /** * The `dd-MMM-yyyy` subfield date — `'02-AUG-1951'` — used by the patient birthdate and the * recording-identification `Startdate`. * * The month is accepted case-insensitively and a two-digit numeric month is accepted too, both * marked non-conformant. The year must be four digits: this field exists precisely to be * unambiguous, so applying the two-digit rule to it would throw away the one thing it is for. */ export declare function parseSubfieldDate(text: string): SubfieldDateParse; /** * Everything that can bear on a start time: both header fields, and the EDF+ `Startdate` that may * override them. All three arrive together because the answer depends on their agreement — a * header date that hit the year escape is only completed by the subfield. */ export interface StartTimeInput { /** The raw eight bytes of the startdate field, as text, padding included. */ readonly rawStartDate: string; /** The raw eight bytes of the starttime field, as text. */ readonly rawStartTime: string; /** From `parseRecordingId`. The only unambiguous four-digit year a file can carry. */ readonly recordingIdDate: EdfCalendarDate | undefined; } /** * Build the whole `EdfStartTime`, including the cross-field resolution. * * The recording-identification date wins when both exist, because its year is unambiguous — * but a disagreement is always reported and both dates stay on the result, so no winner is * picked silently. `dateSource` says which one `resolvedDate` came from. */ export declare function resolveStartTime(input: StartTimeInput, sink: DiagnosticSink): EdfStartTime; /** * `'1951-08-02T09:00:00.000'` — no zone designator, because EDF has no zone. * * The milliseconds are always `.000`: the header stores whole seconds, and the sub-second start * of an EDF+ recording lives in record 0's timekeeping TAL, not here. */ export declare function formatStartTimeNaive(startTime: EdfStartTime): string | undefined; //# sourceMappingURL=dates.d.ts.map