@ultimat3/time 21.0.0 → 22.0.0

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.
package/README.md CHANGED
@@ -158,6 +158,15 @@ negated; an empty one is `0` in either direction, never `-0`.
158
158
  | `X_CRON_NOT_DESCRIBABLE` | a valid 6-field cron whose seconds field `CronPhrases` has no words for |
159
159
  | `X_SCHEDULE_INVALID` | a wall-clock field out of range: `slot.hour`, `slot.minute`, `slot.second`, `slot.weekday` |
160
160
 
161
+ ### Error classes
162
+
163
+ Every error class `src/index.ts` exports, for `instanceof` inside one process. Across a wire or
164
+ a job boundary the class is gone and the `code` is what survives — match on that.
165
+
166
+ | Class | Code | Declared in |
167
+ |---|---|---|
168
+ | `TimeError` | any `TimeErrorCode` — `TIME_ERROR_CODES` | `src/errors.ts` |
169
+
161
170
  ## Why it exists
162
171
 
163
172
  Naive time math breaks quietly: the digest goes out an hour early for half the year, the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ultimat3/time",
3
- "version": "21.0.0",
3
+ "version": "22.0.0",
4
4
  "description": "UTC instants, DST-correct zone math, cron, durations and Intl formatting with an explicit timezone",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -34,6 +34,7 @@
34
34
  "test": "bun test"
35
35
  },
36
36
  "dependencies": {
37
- "@ultimat3/core": "21.0.0"
37
+ "@ultimat3/core": "22.0.0",
38
+ "@ultimat3/schema": "22.0.0"
38
39
  }
39
40
  }
package/src/instant.ts CHANGED
@@ -5,6 +5,7 @@
5
5
  */
6
6
 
7
7
  import { type Clock, systemClock } from '@ultimat3/core';
8
+ import { isIsoDateTime } from '@ultimat3/schema';
8
9
  import { instantInvalid } from './errors';
9
10
 
10
11
  declare const instantBrand: unique symbol;
@@ -25,19 +26,13 @@ export function instant(value: Date): Instant {
25
26
  }
26
27
 
27
28
  /**
28
- * A time of day, and the zone it is stated in. `2026-03-14T09:00` without one is resolved by
29
- * `new Date` through the PROCESS's zone, so the guard has to see both halves: a string carrying
30
- * a clock time is refused unless it also carries `Z` or an offset. A date-only form carries no
31
- * clock time and is UTC by specification, so it passes.
29
+ * ISO-8601 in, `Instant` out. An offset or `Z` is required — a bare local string is refused — and
30
+ * so is anything that is not the ISO shape at all: `new Date` also parses `'March 14, 2026'`,
31
+ * `'3/14/2026'` and `'12'`, each at the HOST's local midnight. The rule is `@ultimat3/schema`'s
32
+ * `isIsoDateTime`, the one `t.date` and HTTP coercion answer with, so the three cannot disagree.
32
33
  */
33
- const CLOCK_TIME = /[t ]\d{1,2}:\d{2}/i;
34
- const UTC_OFFSET = /(?:z|[+-]\d{2}:?\d{2})$/i;
35
-
36
- /** ISO-8601 in, `Instant` out. An offset or `Z` is required — a bare local string is refused. */
37
34
  export function fromIso(iso: string): Instant {
38
- // Enforced, not documented: this header asked for an offset for three releases while the body
39
- // accepted a bare local string and answered a different instant per deployment timezone.
40
- if (CLOCK_TIME.test(iso) && !UTC_OFFSET.test(iso)) throw instantInvalid(iso);
35
+ if (!isIsoDateTime(iso)) throw instantInvalid(iso);
41
36
  const parsed = new Date(iso);
42
37
  if (Number.isNaN(parsed.getTime())) throw instantInvalid(iso);
43
38
  return parsed as Instant;