Skip to content

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-timestamp

Use

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.

FieldTypeInDescription
yearnumberDT, DTMThe year as written, 0 to 9999
monthnumberDT, DTM1 to 12
daynumberDT, DTM1 to the number of days in the month
hournumberTM, DTM0 to 23; always present in a TM
minutenumberTM, DTM0 to 59
secondnumberTM, DTM0 to 59
fractionstringTM, DTMThe 1 to 4 digits after the second, as written: "1230" for .1230
offsetnumberTM, DTMMinutes from UTC, positive east of UTC: -0500 is -300
precisionstringDT, TM, DTMThe last field the value gives, one of the Precision values

Precision

ConstantValueDTM 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.codeMeaningOther fields
invalid-formatThe characters do not follow the datatype's format
month-out-of-rangeThe month is not 01 to 12month
day-out-of-rangeThe day is 00, or past the last day of its monthyear, month, day, daysInMonth
hour-out-of-rangeThe hour is not 00 to 23hour
minute-out-of-rangeThe minute is not 00 to 59minute
second-out-of-rangeThe second is not 00 to 59second
offset-out-of-rangeThe offset's hours are over 14, or its minutes over 59offset, as written, such as "+1500"

A DTM reports the date first, then the time, then the offset.