@glion/util-timestamp 0.15.1 → 0.15.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +36 -78
  2. package/package.json +8 -4
package/README.md CHANGED
@@ -1,22 +1,18 @@
1
1
  # @glion/util-timestamp
2
2
 
3
- An immutable, high-performance HL7v2 timestamp utility with precision tracking. Parses, formats, and converts HL7v2 TS (Time Stamp) values while preserving precision for lossless round-tripping.
3
+ HL7v2 timestamp parser, formatter, and converter with precision tracking.
4
4
 
5
- ## Features
5
+ ## What it does
6
6
 
7
- - **Precision tracking** - 7 levels from year to millisecond, never loses or adds detail
8
- - **Lossless round-trip** - `Timestamp.parse(str).toString() === str` for all valid inputs
9
- - **High performance** - No regex, no intermediate arrays, pre-computed lookup tables
10
- - **Type safe** - Full TypeScript support with const enums and union types
11
- - **Zero dependencies** - Pure computation, no runtime dependencies
7
+ Parses, formats, and converts HL7v2 TS (Time Stamp) values across seven precision levels — year, month, day, hour, minute, second, millisecond — so that `Timestamp.parse(str).toString() === str` for any valid input. Timezone offsets are applied during parsing so `toDate()` returns the correct absolute moment, and reconstructed during formatting so the original local-time representation round-trips exactly regardless of the server's timezone. Pure computation, zero runtime dependencies.
12
8
 
13
- ## Installation
9
+ ## Install
14
10
 
15
11
  ```bash
16
12
  npm install @glion/util-timestamp
17
13
  ```
18
14
 
19
- ## Quick Start
15
+ ## Use
20
16
 
21
17
  ```typescript
22
18
  import { Timestamp, Precision } from "@glion/util-timestamp";
@@ -36,13 +32,13 @@ const now = Timestamp.now({ precision: "second", timezone: true });
36
32
  now.toString(); // "20260307143045+0000"
37
33
  ```
38
34
 
39
- ## API Reference
35
+ ## API
40
36
 
41
37
  ### `Timestamp.parse(value: string): Timestamp`
42
38
 
43
39
  Parses an HL7v2 timestamp string into a `Timestamp` instance.
44
40
 
45
- Accepts the full HL7v2 TS format: `YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ]`
41
+ Accepts the full HL7v2 TS format: `YYYY[MM[DD[HH[MM[SS[.S[S[S[S]]]]]]]]][+/-ZZZZ]`.
46
42
 
47
43
  ```typescript
48
44
  Timestamp.parse("2026"); // year precision
@@ -56,7 +52,7 @@ Timestamp.parse("20260307143045-0500"); // with timezone offset
56
52
  Timestamp.parse("20260307143045.12+0000"); // fractional + timezone
57
53
  ```
58
54
 
59
- **Throws:** `TypeError` if the string is not a valid HL7v2 timestamp.
55
+ Throws `TypeError` if the string is not a valid HL7v2 timestamp.
60
56
 
61
57
  ### `Timestamp.from(date: Date, options?: TimestampOptions): Timestamp`
62
58
 
@@ -71,7 +67,7 @@ Timestamp.from(date, { precision: "millisecond" }).toString(); // "2026030714304
71
67
  Timestamp.from(date, { timezone: true }).toString(); // "20260307143045+0000"
72
68
  ```
73
69
 
74
- **Throws:** `TypeError` if the `Date` is invalid (`NaN`).
70
+ Throws `TypeError` if the `Date` is invalid (`NaN`).
75
71
 
76
72
  ### `Timestamp.now(options?: TimestampOptions): Timestamp`
77
73
 
@@ -84,13 +80,13 @@ Timestamp.now({ precision: "minute" }).toString(); // "202603071430"
84
80
  Timestamp.now({ timezone: true }).toString(); // "20260307143045+0000"
85
81
  ```
86
82
 
87
- ### Instance Properties
83
+ ### Instance properties
88
84
 
89
85
  #### `precision: Precision`
90
86
 
91
87
  The precision level of the timestamp. One of: `"year"`, `"month"`, `"day"`, `"hour"`, `"minute"`, `"second"`, `"millisecond"`.
92
88
 
93
- ### Instance Methods
89
+ ### Instance methods
94
90
 
95
91
  #### `toString(): string`
96
92
 
@@ -130,7 +126,18 @@ Precision.Second; // "second" → YYYYMMDDHHmmss
130
126
  Precision.Millisecond; // "millisecond" → YYYYMMDDHHmmss.SSSS
131
127
  ```
132
128
 
133
- ## Precision Tracking
129
+ ### Error handling
130
+
131
+ All invalid input throws `TypeError` with a descriptive message:
132
+
133
+ ```typescript
134
+ Timestamp.parse(""); // TypeError: Invalid HL7v2 timestamp: ""
135
+ Timestamp.parse("not-a-timestamp"); // TypeError: Invalid HL7v2 timestamp: "not-a-timestamp"
136
+ Timestamp.parse("20263"); // TypeError: Invalid HL7v2 timestamp: "20263"
137
+ Timestamp.from(new Date("invalid")); // TypeError: Invalid Date provided to Timestamp.from
138
+ ```
139
+
140
+ ## Precision model
134
141
 
135
142
  Precision is a first-class concept. The timestamp remembers exactly how much detail was provided, so formatting never inflates or truncates:
136
143
 
@@ -147,43 +154,34 @@ Timestamp.from(date, { precision: "day" }).toString(); // "20260307"
147
154
  Timestamp.from(date, { precision: "minute" }).toString(); // "202603071430"
148
155
  ```
149
156
 
150
- ## Timezone Management
151
-
152
- Timezone information is embedded directly in the `Date` object — not stored as separate public metadata. This ensures that `toDate()` always returns the correct absolute moment, and `toString()` always reproduces the original timezone for lossless round-tripping.
157
+ ### Timezone handling
153
158
 
154
- ### Correct Absolute Moments
159
+ Timezone information is embedded directly in the `Date` object — not stored as separate public metadata. This ensures `toDate()` always returns the correct absolute moment, and `toString()` always reproduces the original timezone for lossless round-tripping.
155
160
 
156
161
  When an HL7v2 timestamp includes a timezone offset (`+/-ZZZZ`), the offset is applied during parsing to construct a `Date` with the correct UTC instant:
157
162
 
158
163
  ```typescript
159
164
  // 14:30:45 in UTC-5 → Date stores 19:30:45 UTC
160
- const ts = Timestamp.parse("20260307143045-0500");
161
- ts.toDate().toISOString(); // "2026-03-07T19:30:45.000Z"
165
+ Timestamp.parse("20260307143045-0500").toDate().toISOString();
166
+ // "2026-03-07T19:30:45.000Z"
162
167
 
163
168
  // 14:30:45 in UTC+5:30 → Date stores 09:00:45 UTC
164
- const ts2 = Timestamp.parse("20260307143045+0530");
165
- ts2.toDate().toISOString(); // "2026-03-07T09:00:45.000Z"
169
+ Timestamp.parse("20260307143045+0530").toDate().toISOString();
170
+ // "2026-03-07T09:00:45.000Z"
166
171
 
167
172
  // Midnight in UTC+5:30 → previous day in UTC
168
- const ts3 = Timestamp.parse("20260101000000+0530");
169
- ts3.toDate().toISOString(); // "2025-12-31T18:30:00.000Z"
173
+ Timestamp.parse("20260101000000+0530").toDate().toISOString();
174
+ // "2025-12-31T18:30:00.000Z"
170
175
  ```
171
176
 
172
- ### Lossless Round-Trip with Timezone
173
-
174
177
  Parsed timestamps with timezone offsets round-trip exactly, regardless of the server's timezone:
175
178
 
176
179
  ```typescript
177
- // On ANY server (UTC, EST, PST, IST):
178
180
  Timestamp.parse("20260307143045-0500").toString(); // "20260307143045-0500"
179
181
  Timestamp.parse("20260307143045+0530").toString(); // "20260307143045+0530"
180
182
  Timestamp.parse("20261231235959.999-0800").toString(); // "20261231235959.999-0800"
181
183
  ```
182
184
 
183
- The timezone offset is stored internally and used by `toString()` to reconstruct the original local time components from UTC. No public `timezoneOffset` property is exposed — this prevents the data integrity risk of consumers calling `toDate()` and forgetting to account for a separate offset.
184
-
185
- ### Creating Timestamps with Timezone
186
-
187
185
  When using `from()` or `now()` with `{ timezone: true }`, the runtime's local timezone offset is captured at creation time:
188
186
 
189
187
  ```typescript
@@ -191,8 +189,6 @@ const ts = Timestamp.from(new Date(), { timezone: true });
191
189
  ts.toString(); // "20260307143045-0500" (on a UTC-5 server)
192
190
  ```
193
191
 
194
- ### Without Timezone
195
-
196
192
  Timestamps without a timezone offset are treated as local time — no UTC conversion is applied:
197
193
 
198
194
  ```typescript
@@ -200,7 +196,7 @@ const ts = Timestamp.parse("20260307143045");
200
196
  // Date is constructed with new Date(2026, 2, 7, 14, 30, 45) — local time
201
197
  ```
202
198
 
203
- ### Precision Gate
199
+ ### Precision gate on timezone
204
200
 
205
201
  Timezone is only included at `"hour"` precision or finer. Coarser precisions (`"year"`, `"month"`, `"day"`) never carry a timezone suffix:
206
202
 
@@ -212,47 +208,9 @@ Timestamp.from(date, { precision: "hour", timezone: true }).toString();
212
208
  // "2026030714-0500" — timezone included
213
209
  ```
214
210
 
215
- ## Performance
216
-
217
- Optimized for high-throughput streaming processors handling 100K+ messages per second:
218
-
219
- - **No regex** — manual character-based parsing via `codePointAt` arithmetic
220
- - **No intermediate arrays** — direct string concatenation in `toString()`
221
- - **Pre-computed lookup table** — zero-padded strings for 0-99
222
- - **O(1) precision lookups** — `Map` instead of `Array.indexOf()`
223
- - **Zero allocations in hot paths** — no substring extraction or `Number()` conversions
224
-
225
- ## Error Handling
226
-
227
- All invalid input throws `TypeError` with a descriptive message:
228
-
229
- ```typescript
230
- Timestamp.parse(""); // TypeError: Invalid HL7v2 timestamp: ""
231
- Timestamp.parse("not-a-timestamp"); // TypeError: Invalid HL7v2 timestamp: "not-a-timestamp"
232
- Timestamp.parse("20263"); // TypeError: Invalid HL7v2 timestamp: "20263"
233
- Timestamp.from(new Date("invalid")); // TypeError: Invalid Date provided to Timestamp.from
234
- ```
235
-
236
- ## Contributing
237
-
238
- We welcome contributions! Please see our [Contributing Guide][github-contributing] for more details.
239
-
240
- 1. Fork the repository
241
- 2. Create your feature branch (`git checkout -b feature/amazing-feature`)
242
- 3. Commit your changes (`git commit -m 'Add some amazing feature'`)
243
- 4. Push to the branch (`git push origin feature/amazing-feature`)
244
- 5. Open a Pull Request
245
-
246
- ## Code of Conduct
247
-
248
- To ensure a welcoming and positive environment, we have a [Code of Conduct][github-code-of-conduct] that all contributors and participants are expected to adhere to.
249
-
250
- ## License
251
-
252
- Copyright 2025 Rethink Health, SUARL. All rights reserved.
211
+ ## Part of Glion
253
212
 
254
- This program is licensed to you under the terms of the [MIT License](https://opensource.org/licenses/MIT). This program is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the [LICENSE][github-license] file for details.
213
+ `@glion/util-timestamp` is part of **[Glion]**, the application framework for HL7v2. See the [Glion README] for the full package catalog and architecture.
255
214
 
256
- [github-code-of-conduct]: https://github.com/rethinkhealth/glion/blob/main/CODE_OF_CONDUCT.md
257
- [github-license]: https://github.com/rethinkhealth/glion/blob/main/LICENSE
258
- [github-contributing]: https://github.com/rethinkhealth/glion/blob/main/CONTRIBUTING.md
215
+ [Glion]: https://github.com/rethinkhealth/glion#readme
216
+ [Glion README]: https://github.com/rethinkhealth/glion#readme
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@glion/util-timestamp",
3
- "version": "0.15.1",
3
+ "version": "0.15.3",
4
4
  "description": "HL7v2 timestamp parsing, formatting, and conversion with precision tracking",
5
5
  "keywords": [
6
6
  "health",
@@ -36,11 +36,13 @@
36
36
  "devDependencies": {
37
37
  "@types/node": "^25.5.0",
38
38
  "@vitest/coverage-v8": "4.1.2",
39
+ "publint": "0.3.18",
39
40
  "tsdown": "0.21.7",
40
41
  "typescript": "^5.9.3",
41
42
  "vitest": "4.1.2",
42
- "@glion/testing": "0.15.1",
43
- "@glion/tsconfig": "0.15.1"
43
+ "@glion/check-readme": "0.15.3",
44
+ "@glion/testing": "0.15.3",
45
+ "@glion/tsconfig": "0.15.3"
44
46
  },
45
47
  "engines": {
46
48
  "node": ">=18"
@@ -49,8 +51,10 @@
49
51
  "scripts": {
50
52
  "build": "tsdown && tsc --emitDeclarationOnly",
51
53
  "check-types": "tsc --noEmit",
54
+ "check:readme": "glion-check-readme",
52
55
  "test": "vitest run",
53
56
  "test:coverage": "vitest run --coverage",
54
- "test:watch": "vitest"
57
+ "test:watch": "vitest",
58
+ "publint": "publint --strict"
55
59
  }
56
60
  }