Timestamp utility
HL7v2 timestamp parser, formatter, and converter with precision tracking.
HL7v2 DT, TM, and DTM parser and formatter with precision and calendar checks.
What it does
Reads an HL7v2 DT (Date), TM (Time), or DTM (Date/Time) value into a plain object holding the fields the value gives, and writes such an object back as HL7v2 text. A value keeps its precision: 202603 is March 2026, with no day. A parse checks the format and the calendar, so 20250229 fails because 2025 is not a leap year. Parsing never throws: it returns the value or the reason it is not valid. The fields are the sender's local time, with the offset when the value gives one. Pure computation, zero runtime dependencies.
Install
npm install @glion/util-timestampUse
import { formatDTM, parseDTM } from "@glion/util-timestamp";
const result = parseDTM("20260307143045-0500");
// { success: true, data: { year: 2026, month: 3, day: 7, hour: 14,
// minute: 30, second: 45, offset: -300, precision: "second" } }
if (result.success) {
formatDTM(result.data); // "20260307143045-0500"
}
parseDTM("20250229");
// { success: false, issue: { code: "day-out-of-range", year: 2025,
// month: 2, day: 29, daysInMonth: 28 } }API
parseDT(value: string): ParseResult<DT>
Parses a DT value, YYYY[MM[DD]].
parseDT("202603"); // { success: true, data: { year: 2026, month: 3, precision: "month" } }
parseDT("2026-03-07"); // { success: false, issue: { code: "invalid-format" } }parseTM(value: string): ParseResult<TM>
Parses a TM value, HH[MM[SS[.S[S[S[S]]]]]][+/-ZZZZ].
parseTM("1430-0500"); // { success: true, data: { hour: 14, minute: 30, offset: -300, precision: "minute" } }
parseTM("2400"); // { success: false, issue: { code: "hour-out-of-range", hour: 24 } }parseDTM(value: string): ParseResult<DTM>
Parses a DTM value, YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ], or the TS.1 of a TS. The date is checked as written, before the offset applies.
parseDTM("20260307143045.12"); // { success: true, data: { ..., second: 45, fraction: "12", precision: "second" } }
parseDTM("20261307"); // { success: false, issue: { code: "month-out-of-range", month: 13 } }formatDT(date: DT): string, formatTM(time: TM): string, formatDTM(dateTime: DTM): string
Write a value as HL7v2 text, with the fields it has. For every valid value, formatDTM(parseDTM(value).data) === value, and the same for DT and TM, except that an offset of -0000 is written +0000.
formatDT({ year: 2026, month: 3, precision: "month" }); // "202603"
formatTM({ hour: 9, offset: 345, precision: "hour" }); // "09+0545"
formatDTM({ year: 99, precision: "year" }); // "0099"DT, TM, DTM
The parsed value. A field is present only when the value gives it.
| Field | Type | In | Description |
|---|---|---|---|
year | number | DT, DTM | The year as written, 0 to 9999 |
month | number | DT, DTM | 1 to 12 |
day | number | DT, DTM | 1 to the number of days in the month |
hour | number | TM, DTM | 0 to 23; always present in a TM |
minute | number | TM, DTM | 0 to 59 |
second | number | TM, DTM | 0 to 59 |
fraction | string | TM, DTM | The 1 to 4 digits after the second, as written: "1230" for .1230 |
offset | number | TM, DTM | Minutes from UTC, positive east of UTC: -0500 is -300 |
precision | string | DT, TM, DTM | The last field the value gives, one of the Precision values |
Precision
| Constant | Value | DTM written as |
|---|---|---|
Precision.Year | "year" | YYYY |
Precision.Month | "month" | YYYYMM |
Precision.Day | "day" | YYYYMMDD |
Precision.Hour | "hour" | YYYYMMDDHH |
Precision.Minute | "minute" | YYYYMMDDHHMM |
Precision.Second | "second" | YYYYMMDDHHMMSS |
A DT is year, month, or day; a TM is hour, minute, or second. Digits after the second are in fraction.
ParseResult<T> and TimestampIssue
type ParseResult<T> =
{ success: true; data: T } | { success: false; issue: TimestampIssue };issue.code | Meaning | Other fields |
|---|---|---|
invalid-format | The characters do not follow the datatype's format | |
month-out-of-range | The month is not 01 to 12 | month |
day-out-of-range | The day is 00, or past the last day of its month | year, month, day, daysInMonth |
hour-out-of-range | The hour is not 00 to 23 | hour |
minute-out-of-range | The minute is not 00 to 59 | minute |
second-out-of-range | The second is not 00 to 59 | second |
offset-out-of-range | The offset's hours are over 14, or its minutes over 59 | offset, as written, such as "+1500" |
A DTM reports the date first, then the time, then the offset.