@northguild/gmt 1.14.2 → 1.15.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.
Files changed (137) hide show
  1. package/README.md +43 -13
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +1 -0
  4. package/dist/plain/calculate/diffDateAsDuration.js +1 -1
  5. package/dist/plain/calculate/index.d.ts +2 -1
  6. package/dist/plain/calculate/index.js +2 -1
  7. package/dist/plain/calculate/{weekOfYear.d.ts → weekOfYearForDate.d.ts} +0 -14
  8. package/dist/plain/calculate/weekOfYearForDate.js +28 -0
  9. package/dist/plain/calculate/weekOfYearForDateTime.d.ts +14 -0
  10. package/dist/plain/calculate/{weekOfYear.js → weekOfYearForDateTime.js} +1 -27
  11. package/dist/plain/format/formatCalendar.d.ts +2 -2
  12. package/dist/plain/format/formatDate.d.ts +3 -2
  13. package/dist/plain/format/formatDate.js +1 -1
  14. package/dist/plain/format/formatDateRange.d.ts +3 -2
  15. package/dist/plain/format/formatDateRange.js +1 -1
  16. package/dist/plain/format/formatDateTime.d.ts +3 -2
  17. package/dist/plain/format/formatDateTime.js +1 -1
  18. package/dist/plain/format/formatDateTimeRange.d.ts +3 -2
  19. package/dist/plain/format/formatDateTimeRange.js +1 -1
  20. package/dist/plain/format/formatDateTimeToParts.d.ts +3 -2
  21. package/dist/plain/format/formatDateTimeToParts.js +1 -1
  22. package/dist/plain/format/formatDateToParts.d.ts +3 -2
  23. package/dist/plain/format/formatDateToParts.js +1 -1
  24. package/dist/plain/format/formatRelativeDate.d.ts +3 -14
  25. package/dist/plain/format/formatRelativeDateTime.d.ts +3 -14
  26. package/dist/plain/format/formatRelativeTime.d.ts +3 -14
  27. package/dist/plain/format/formatTime.d.ts +2 -1
  28. package/dist/plain/get/getNowUnit.d.ts +2 -3
  29. package/dist/plain/interval/splitIntervalByUnitDate.js +1 -1
  30. package/dist/regex/calendar-date.d.ts +19 -0
  31. package/dist/regex/calendar-date.js +19 -10
  32. package/dist/regex/calendar-zoned-date-time.d.ts +45 -0
  33. package/dist/regex/calendar-zoned-date-time.js +45 -40
  34. package/dist/regex/date-time.d.ts +18 -0
  35. package/dist/regex/date-time.js +18 -1
  36. package/dist/regex/date.d.ts +16 -0
  37. package/dist/regex/date.js +16 -1
  38. package/dist/regex/http-date.d.ts +15 -0
  39. package/dist/regex/http-date.js +15 -6
  40. package/dist/regex/leap-second.d.ts +12 -0
  41. package/dist/regex/leap-second.js +12 -1
  42. package/dist/regex/rfc-2822.d.ts +18 -0
  43. package/dist/regex/rfc-2822.js +18 -8
  44. package/dist/regex/rfc-3339.d.ts +19 -0
  45. package/dist/regex/rfc-3339.js +19 -6
  46. package/dist/regex/sql-date-time.d.ts +14 -0
  47. package/dist/regex/sql-date-time.js +14 -6
  48. package/dist/regex/time-zone-like.d.ts +21 -0
  49. package/dist/regex/time-zone-like.js +21 -0
  50. package/dist/regex/time.d.ts +59 -0
  51. package/dist/regex/time.js +59 -3
  52. package/dist/regex/unix.d.ts +21 -0
  53. package/dist/regex/unix.js +21 -0
  54. package/dist/regex/utc-date-time.d.ts +20 -0
  55. package/dist/regex/utc-date-time.js +20 -1
  56. package/dist/types/calendar-options.d.ts +11 -0
  57. package/dist/types/calendar-options.js +0 -0
  58. package/dist/types/datetime-format-options.d.ts +6 -0
  59. package/dist/types/datetime-format-options.js +0 -0
  60. package/dist/types/duration-unit.d.ts +5 -0
  61. package/dist/types/duration-unit.js +0 -0
  62. package/dist/types/index.d.ts +11 -0
  63. package/dist/types/index.js +11 -0
  64. package/dist/types/now-unit.d.ts +5 -0
  65. package/dist/types/now-unit.js +0 -0
  66. package/dist/types/relative-date-time-unit.d.ts +6 -0
  67. package/dist/types/relative-date-time-unit.js +0 -0
  68. package/dist/types/relative-date-unit.d.ts +5 -0
  69. package/dist/types/relative-date-unit.js +0 -0
  70. package/dist/types/relative-time-options.d.ts +18 -0
  71. package/dist/types/relative-time-options.js +0 -0
  72. package/dist/types/relative-time-unit.d.ts +5 -0
  73. package/dist/types/relative-time-unit.js +0 -0
  74. package/dist/types/relative-unit.d.ts +6 -0
  75. package/dist/types/relative-unit.js +0 -0
  76. package/dist/types/unix-now-unit.d.ts +5 -0
  77. package/dist/types/unix-now-unit.js +0 -0
  78. package/dist/types/utc-now-unit.d.ts +5 -0
  79. package/dist/types/utc-now-unit.js +0 -0
  80. package/dist/unix/calculate/startOrEndOfUnix.d.ts +18 -0
  81. package/dist/unix/calculate/startOrEndOfUnix.js +18 -0
  82. package/dist/unix/format/formatCalendarUnix.d.ts +27 -1
  83. package/dist/unix/format/formatRelativeUnix.d.ts +1 -8
  84. package/dist/unix/format/formatUnix.d.ts +19 -0
  85. package/dist/unix/format/formatUnix.js +19 -0
  86. package/dist/unix/get/getUnixNowUnit.d.ts +2 -3
  87. package/dist/unix/parse/parseUnitFromUnix.d.ts +24 -0
  88. package/dist/unix/validate/isValidUnixUnit.d.ts +15 -0
  89. package/dist/utc/calculate/startOrEndOfUtc.d.ts +17 -0
  90. package/dist/utc/calculate/startOrEndOfUtc.js +17 -0
  91. package/dist/utc/format/formatCalendarUtc.d.ts +2 -2
  92. package/dist/utc/format/formatRelativeUtc.d.ts +2 -12
  93. package/dist/utc/format/formatUtc.d.ts +33 -0
  94. package/dist/utc/format/formatUtc.js +17 -0
  95. package/dist/utc/get/getUtcNowUnit.d.ts +2 -3
  96. package/dist/utc/parse/parseUnitFromUtc.d.ts +23 -0
  97. package/dist/zoned/format/formatRelativeZoned.d.ts +1 -8
  98. package/dist/zoned/format/formatTimeZoneName.d.ts +15 -0
  99. package/dist/zoned/format/formatZonedDateTime.d.ts +2 -1
  100. package/dist/zoned/format/formatZonedRange.d.ts +2 -1
  101. package/dist/zoned/format/formatZonedToParts.d.ts +2 -1
  102. package/dist/zoned/get/getDstTransitions.d.ts +18 -2
  103. package/dist/zoned/get/getZonedNowUnit.d.ts +24 -0
  104. package/dist/zoned/interval/intervalDifferenceZoned.d.ts +3 -3
  105. package/dist/zoned/interval/intervalDifferenceZoned.js +3 -3
  106. package/dist/zoned/interval/intervalXorZoned.d.ts +6 -4
  107. package/dist/zoned/interval/intervalXorZoned.js +6 -4
  108. package/dist/zoned/parse/getZonedOffsetAs.d.ts +11 -0
  109. package/dist/zoned/parse/parseUnitFromZoned.d.ts +24 -0
  110. package/package.json +25 -7
  111. package/skills/gmt-arithmetic/SKILL.md +83 -0
  112. package/skills/gmt-basics/SKILL.md +80 -0
  113. package/skills/gmt-integration/SKILL.md +73 -0
  114. package/skills/gmt-timezone/SKILL.md +80 -0
  115. package/skills/_artifacts/domain_map.yaml +0 -547
  116. package/skills/_artifacts/skill_spec.md +0 -67
  117. package/skills/_artifacts/skill_tree.yaml +0 -278
  118. package/skills/api-expansion-workflow/SKILL.md +0 -52
  119. package/skills/app-integration/SKILL.md +0 -38
  120. package/skills/calculate-dates/SKILL.md +0 -432
  121. package/skills/compare-dates/SKILL.md +0 -412
  122. package/skills/convert-types/SKILL.md +0 -305
  123. package/skills/durations/SKILL.md +0 -418
  124. package/skills/format-date-time/SKILL.md +0 -486
  125. package/skills/format-date-time/references/format-api.md +0 -34
  126. package/skills/format-relative-time/SKILL.md +0 -223
  127. package/skills/get-current/SKILL.md +0 -229
  128. package/skills/interval-ops/SKILL.md +0 -432
  129. package/skills/issue-creation/SKILL.md +0 -118
  130. package/skills/lint-package-suggestion/SKILL.md +0 -37
  131. package/skills/new-method-implementation/SKILL.md +0 -71
  132. package/skills/parse-date-time/SKILL.md +0 -349
  133. package/skills/pr-contribution/SKILL.md +0 -180
  134. package/skills/unit-test-generation/SKILL.md +0 -56
  135. package/skills/validate-dates/SKILL.md +0 -438
  136. package/skills/zoned-date-ops/SKILL.md +0 -422
  137. package/skills/zoned-date-ops/references/timezones.md +0 -13
@@ -1,438 +0,0 @@
1
- ---
2
- name: validate-dates
3
- description: >
4
- Validate date/time strings, timezone identifiers, intervals, or ranges. Use
5
- isValidDate, isValidTime, isValidDateTime, isValidDateInterval,
6
- isValidTimeInterval, isValidDateTimeInterval for scalar and interval
7
- validation. Use hasDaylightSaving to check whether an IANA timezone observes
8
- daylight saving time. Use getDstTransitions to enumerate DST transition
9
- instants for a timezone in a given year. Use intervalContains*,
10
- intervalUnion*, and splitIntervalByUnit* for interval containment, merging,
11
- and splitting. All validation functions return false on invalid input;
12
- interval union returns null on disjoint or invalid input; split functions
13
- return [] on invalid input.
14
- sources:
15
- - 'northguild/gmt:packages/gmt/src/plain/validate/index.ts'
16
- - 'northguild/gmt:packages/gmt/src/plain/interval/validate/index.ts'
17
- - 'northguild/gmt:packages/gmt/src/plain/interval/intervalContainsDate.ts'
18
- - 'northguild/gmt:packages/gmt/src/plain/interval/intervalContainsTime.ts'
19
- - 'northguild/gmt:packages/gmt/src/plain/interval/intervalContainsDateTime.ts'
20
- - 'northguild/gmt:packages/gmt/src/plain/interval/intervalUnionDate.ts'
21
- - 'northguild/gmt:packages/gmt/src/plain/interval/intervalUnionTime.ts'
22
- - 'northguild/gmt:packages/gmt/src/plain/interval/intervalUnionDateTime.ts'
23
- - 'northguild/gmt:packages/gmt/src/plain/interval/splitIntervalByUnitDate.ts'
24
- - 'northguild/gmt:packages/gmt/src/plain/interval/splitIntervalByUnitTime.ts'
25
- - 'northguild/gmt:packages/gmt/src/plain/interval/splitIntervalByUnitDateTime.ts'
26
- - 'northguild/gmt:packages/gmt/src/utc/validate/index.ts'
27
- - 'northguild/gmt:packages/gmt/src/utc/interval/validate/index.ts'
28
- - 'northguild/gmt:packages/gmt/src/utc/interval/intervalContainsUtc.ts'
29
- - 'northguild/gmt:packages/gmt/src/utc/interval/intervalUnionUtc.ts'
30
- - 'northguild/gmt:packages/gmt/src/utc/interval/splitIntervalByUnitUtc.ts'
31
- - 'northguild/gmt:packages/gmt/src/unix/validate/index.ts'
32
- - 'northguild/gmt:packages/gmt/src/unix/interval/validate/index.ts'
33
- - 'northguild/gmt:packages/gmt/src/unix/interval/intervalContainsUnix.ts'
34
- - 'northguild/gmt:packages/gmt/src/unix/interval/intervalUnionUnix.ts'
35
- - 'northguild/gmt:packages/gmt/src/unix/interval/splitIntervalByUnitUnix.ts'
36
- - 'northguild/gmt:packages/gmt/src/zoned/validate/index.ts'
37
- - 'northguild/gmt:packages/gmt/src/zoned/validate/hasDaylightSaving.ts'
38
- - 'northguild/gmt:packages/gmt/src/zoned/get/getDstTransitions.ts'
39
- - 'northguild/gmt:packages/gmt/src/zoned/interval/validate/index.ts'
40
- - 'northguild/gmt:packages/gmt/src/zoned/interval/intervalContainsZoned.ts'
41
- - 'northguild/gmt:packages/gmt/src/zoned/interval/intervalUnionZoned.ts'
42
- - 'northguild/gmt:packages/gmt/src/zoned/interval/splitIntervalByUnitZoned.ts'
43
- metadata:
44
- type: core
45
- library: '@northguild/gmt'
46
- library_version: '1.14.2'
47
- ---
48
-
49
- # Validate Dates
50
-
51
- Use this skill when you need to validate date, time, or datetime strings before processing.
52
-
53
- ## Setup
54
-
55
- ```ts
56
- import { isValidDate, isValidTime, isValidDateTime } from "@northguild/gmt";
57
- import { isValidTimeZone, isValidZonedDateTime } from "@northguild/gmt/zoned";
58
- ```
59
-
60
- ## Core Patterns
61
-
62
- ### Validate ISO date string
63
-
64
- ```ts
65
- const valid = isValidDate("2024-03-15"); // true
66
- const invalid = isValidDate("2024-02-30"); // false (invalid day)
67
- const invalidFormat = isValidDate("invalid"); // false
68
- ```
69
-
70
- ### Validate ISO time string
71
-
72
- ```ts
73
- import { isValidTime } from "@northguild/gmt";
74
-
75
- const valid = isValidTime("14:30:45"); // true
76
- const invalid = isValidTime("25:00:00"); // false (invalid hour)
77
- const invalidFormat = isValidTime("not a time"); // false
78
- ```
79
-
80
- ### Validate ISO datetime string
81
-
82
- ```ts
83
- import { isValidDateTime } from "@northguild/gmt";
84
-
85
- const valid = isValidDateTime("2024-03-15T14:30:45"); // true
86
- const invalid = isValidDateTime("2024-02-30T14:30:45"); // false
87
- ```
88
-
89
- ### Validate IANA timezone
90
-
91
- ```ts
92
- import { isValidTimeZone } from "@northguild/gmt/zoned";
93
-
94
- const valid = isValidTimeZone("America/New_York"); // true
95
- const invalid = isValidTimeZone("Invalid/Zone"); // false
96
- ```
97
-
98
- ### Validate zoned datetime string
99
-
100
- ```ts
101
- import { isValidZonedDateTime } from "@northguild/gmt/zoned";
102
-
103
- const valid = isValidZonedDateTime("2024-03-15T14:30:45[America/New_York]"); // true
104
- const invalid = isValidZonedDateTime("2024-02-30T14:30:45[America/New_York]"); // false
105
-
106
- // E5 (issue #78): a [u-ca=...] calendar annotation is always invalid here — calendar-system
107
- // awareness is plain/ PlainDate only. Same rejection applies to isValidZonedInterval below and
108
- // every zoned/interval/* function.
109
- const rejected = isValidZonedDateTime(
110
- "2024-03-15T14:30:45-04:00[America/New_York][u-ca=hebrew]",
111
- ); // false
112
- ```
113
-
114
- ### Check daylight saving time
115
-
116
- ```ts
117
- import { hasDaylightSaving } from "@northguild/gmt/zoned";
118
-
119
- const hasDst = hasDaylightSaving("America/New_York"); // true
120
- const noDst = hasDaylightSaving("Asia/Tokyo"); // false
121
- const invalid = hasDaylightSaving("Invalid/Zone"); // false
122
- ```
123
-
124
- ### List DST transition instants
125
-
126
- ```ts
127
- import { getDstTransitions } from "@northguild/gmt/zoned";
128
-
129
- const transitions = getDstTransitions("America/New_York", 2024);
130
- // [
131
- // { instant: "2024-03-10T07:00:00Z", offsetBefore: "-05:00", offsetAfter: "-04:00" },
132
- // { instant: "2024-11-03T06:00:00Z", offsetBefore: "-04:00", offsetAfter: "-05:00" }
133
- // ]
134
-
135
- const noTransitions = getDstTransitions("Asia/Tokyo", 2024);
136
- // []
137
- ```
138
-
139
- ### Validate date duration unit
140
-
141
- ```ts
142
- import { isValidDateUnit } from "@northguild/gmt";
143
-
144
- const valid = isValidDateUnit("day"); // true
145
- const valid = isValidDateUnit("month"); // true
146
- const valid = isValidDateUnit("year"); // true
147
- const invalid = isValidDateUnit("invalid"); // false
148
- ```
149
-
150
- ### Validate time duration unit
151
-
152
- ```ts
153
- import { isValidTimeUnit } from "@northguild/gmt";
154
-
155
- const valid = isValidTimeUnit("hour"); // true
156
- const valid = isValidTimeUnit("minute"); // true
157
- const invalid = isValidTimeUnit("invalid"); // false
158
- ```
159
-
160
- ### Validate date interval
161
-
162
- ```ts
163
- import { isValidDateInterval } from "@northguild/gmt";
164
-
165
- const valid = isValidDateInterval("2024-01-01", "2024-12-31"); // true
166
- const invalid = isValidDateInterval("2024-12-31", "2024-01-01"); // false (start > end)
167
- const invalid = isValidDateInterval("not-a-date", "2024-12-31"); // false
168
-
169
- // E5 (issue #78): accepts GMT calendar-annotated PlainDate strings, and start/end may carry
170
- // different calendars — ordering is calendar-independent.
171
- const mixedCalendars = isValidDateInterval(
172
- "5785-01-01[u-ca=hebrew]",
173
- "2024-12-31",
174
- ); // true
175
- ```
176
-
177
- ### Validate time interval
178
-
179
- ```ts
180
- import { isValidTimeInterval } from "@northguild/gmt";
181
-
182
- const valid = isValidTimeInterval("09:00:00", "17:00:00"); // true
183
- const invalid = isValidTimeInterval("25:00:00", "17:00:00"); // false (invalid start)
184
- ```
185
-
186
- ### Validate datetime interval
187
-
188
- ```ts
189
- import { isValidDateTimeInterval } from "@northguild/gmt";
190
-
191
- const valid = isValidDateTimeInterval("2024-01-01T09:00:00", "2024-12-31T17:00:00"); // true
192
- const invalid = isValidDateTimeInterval("2024-12-31T17:00:00", "2024-01-01T09:00:00"); // false
193
- ```
194
-
195
- ### Validate UTC interval
196
-
197
- ```ts
198
- import { isValidUtcInterval } from "@northguild/gmt/utc";
199
-
200
- const valid = isValidUtcInterval("2024-01-01T09:00:00Z", "2024-12-31T17:00:00Z"); // true
201
- const invalid = isValidUtcInterval("2024-12-31T17:00:00Z", "2024-01-01T09:00:00Z"); // false
202
- ```
203
-
204
- ### Validate Unix interval
205
-
206
- ```ts
207
- import { isValidUnixInterval } from "@northguild/gmt/unix";
208
-
209
- const valid = isValidUnixInterval("1704067200", "1704067800"); // true (seconds)
210
- const validMs = isValidUnixInterval("1704067200000", "1704067800000"); // true (milliseconds)
211
- const invalid = isValidUnixInterval("1704067800", "1704067200"); // false
212
- ```
213
-
214
- ### Validate zoned interval
215
-
216
- ```ts
217
- import { isValidZonedInterval } from "@northguild/gmt/zoned";
218
-
219
- const valid = isValidZonedInterval(
220
- "2024-01-01T09:00:00+00:00[UTC]",
221
- "2024-12-31T17:00:00+00:00[UTC]"
222
- ); // true
223
- const invalid = isValidZonedInterval(
224
- "2024-12-31T17:00:00+00:00[UTC]",
225
- "2024-01-01T09:00:00+00:00[UTC]"
226
- ); // false
227
- ```
228
-
229
- ### Check point-in-interval (3-arg)
230
-
231
- ```ts
232
- import { intervalContainsDate } from "@northguild/gmt";
233
-
234
- const inside = intervalContainsDate("2024-01-01", "2024-12-31", "2024-06-15"); // true
235
- const onBoundary = intervalContainsDate("2024-01-01", "2024-12-31", "2024-01-01"); // true
236
- const outside = intervalContainsDate("2024-01-01", "2024-12-31", "2025-01-01"); // false
237
- ```
238
-
239
- ### Check interval-in-interval (4-arg)
240
-
241
- ```ts
242
- import { intervalContainsDate } from "@northguild/gmt";
243
-
244
- const inside = intervalContainsDate("2024-01-01", "2024-12-31", "2024-03-01", "2024-09-01"); // true
245
- const equal = intervalContainsDate("2024-01-01", "2024-12-31", "2024-01-01", "2024-12-31"); // true
246
- const partial = intervalContainsDate("2024-01-01", "2024-12-31", "2024-06-15", "2025-01-01"); // false
247
- ```
248
-
249
- ### Check time interval containment
250
-
251
- ```ts
252
- import { intervalContainsTime } from "@northguild/gmt";
253
-
254
- const inside = intervalContainsTime("09:00:00", "17:00:00", "12:00:00"); // true
255
- const inner = intervalContainsTime("09:00:00", "17:00:00", "10:00:00", "16:00:00"); // true
256
- ```
257
-
258
- ### Check datetime interval containment
259
-
260
- ```ts
261
- import { intervalContainsDateTime } from "@northguild/gmt";
262
-
263
- const inside = intervalContainsDateTime("2024-01-01T10:00:00", "2024-12-31T23:59:59", "2024-06-15T12:00:00"); // true
264
- const inner = intervalContainsDateTime("2024-01-01T10:00:00", "2024-12-31T23:59:59", "2024-03-01T00:00:00", "2024-09-01T00:00:00"); // true
265
- ```
266
-
267
- ### Check UTC interval containment
268
-
269
- ```ts
270
- import { intervalContainsUtc } from "@northguild/gmt/utc";
271
-
272
- const inside = intervalContainsUtc("2024-01-01T00:00:00Z", "2024-12-31T23:59:59Z", "2024-06-15T12:00:00Z"); // true
273
- const inner = intervalContainsUtc("2024-01-01T00:00:00Z", "2024-12-31T23:59:59Z", "2024-03-01T00:00:00Z", "2024-09-01T00:00:00Z"); // true
274
- ```
275
-
276
- ### Check Unix interval containment
277
-
278
- ```ts
279
- import { intervalContainsUnix } from "@northguild/gmt/unix";
280
-
281
- const inside = intervalContainsUnix(0, 1700000000, 170000000); // true
282
- const inner = intervalContainsUnix(0, 1700000000, 100000, 1000000); // true
283
- const stringInput = intervalContainsUnix("0", "1700000000", "170000000"); // true
284
- ```
285
-
286
- ### Check zoned interval containment
287
-
288
- ```ts
289
- import { intervalContainsZoned } from "@northguild/gmt/zoned";
290
-
291
- const inside = intervalContainsZoned("2024-01-01T00:00:00+00:00[UTC]", "2024-12-31T23:59:59+00:00[UTC]", "2024-06-15T12:00:00+00:00[UTC]"); // true
292
- const inner = intervalContainsZoned("2024-01-01T00:00:00+00:00[UTC]", "2024-12-31T23:59:59+00:00[UTC]", "2024-03-01T00:00:00+00:00[UTC]", "2024-09-01T00:00:00+00:00[UTC]"); // true
293
- ```
294
-
295
- ### Merge overlapping or adjacent intervals (union)
296
-
297
- ```ts
298
- import { intervalUnionDate } from "@northguild/gmt";
299
-
300
- const merged = intervalUnionDate("2024-01-01", "2024-06-30", "2024-04-01", "2024-12-31");
301
- // { start: "2024-01-01", end: "2024-12-31" }
302
-
303
- const adjacent = intervalUnionDate("2024-01-01", "2024-06-30", "2024-06-30", "2024-12-31");
304
- // { start: "2024-01-01", end: "2024-12-31" } — adjacent intervals ARE merged
305
-
306
- const disjoint = intervalUnionDate("2024-01-01", "2024-06-30", "2024-07-01", "2024-12-31");
307
- // null — gap between intervals
308
- ```
309
-
310
- `intervalUnionTime`, `intervalUnionDateTime`, `intervalUnionUtc`, `intervalUnionUnix`, and `intervalUnionZoned` follow the same pattern across their respective types. Unix returns `{ start: number; end: number } | null`; all others return `{ start: string; end: string } | null`.
311
-
312
- ### Split interval into sub-intervals by unit
313
-
314
- ```ts
315
- import { splitIntervalByUnitDate } from "@northguild/gmt";
316
-
317
- const slices = splitIntervalByUnitDate("2024-01-01", "2024-01-10", "day", 2);
318
- // [
319
- // { start: "2024-01-01", end: "2024-01-03" },
320
- // { start: "2024-01-03", end: "2024-01-05" },
321
- // { start: "2024-01-05", end: "2024-01-07" },
322
- // { start: "2024-01-07", end: "2024-01-09" },
323
- // { start: "2024-01-09", end: "2024-01-10" }
324
- // ]
325
- ```
326
-
327
- `splitIntervalByUnitTime`, `splitIntervalByUnitDateTime`, `splitIntervalByUnitUtc`, `splitIntervalByUnitUnix`, and `splitIntervalByUnitZoned` follow the same pattern. The final sub-interval is trimmed so its `end` never exceeds the original `end`. All split functions return `[]` on invalid input (wrong type, malformed strings, leap seconds, inverted intervals, non-positive amount, unsupported unit, or a unit that has no effect on the target type).
328
-
329
- ## Common Mistakes
330
-
331
- ### HIGH Not validating before parsing
332
-
333
- Wrong:
334
-
335
- ```ts
336
- const date = Temporal.PlainDate.from(input); // may throw
337
- ```
338
-
339
- Correct:
340
-
341
- ```ts
342
- import { isValidDate } from "@northguild/gmt";
343
-
344
- if (!isValidDate(input)) {
345
- throw new Error("Invalid date");
346
- }
347
- const date = Temporal.PlainDate.from(input);
348
- ```
349
-
350
- Source: AGENTS.md — Always validate before parsing
351
-
352
- ### HIGH Not validating timezone before use
353
-
354
- Wrong:
355
-
356
- ```ts
357
- const zoned = Temporal.ZonedDateTime.from("2024-03-15T14:30:45[Invalid/Zone]"); // may throw
358
- ```
359
-
360
- Correct:
361
-
362
- ```ts
363
- import { isValidTimeZone } from "@northguild/gmt/zoned";
364
-
365
- if (!isValidTimeZone("America/New_York")) {
366
- throw new Error("Invalid timezone");
367
- }
368
- const zoned = Temporal.ZonedDateTime.from("2024-03-15T14:30:45[America/New_York]");
369
- ```
370
-
371
- Source: packages/gmt/src/zoned/validate/isValidTimeZone.ts — Validates IANA timezone
372
-
373
- ### MEDIUM Using try-catch for validation
374
-
375
- Wrong:
376
-
377
- ```ts
378
- let valid = false;
379
- try {
380
- Temporal.PlainDate.from(input);
381
- valid = true;
382
- } catch {
383
- valid = false;
384
- }
385
- ```
386
-
387
- Correct:
388
-
389
- ```ts
390
- import { isValidDate } from "@northguild/gmt";
391
-
392
- const valid = isValidDate(input);
393
- ```
394
-
395
- Source: AGENTS.md — Use validation functions, not exceptions for flow
396
-
397
- ### MEDIUM Confusing range validators with interval validators
398
-
399
- Wrong:
400
-
401
- ```ts
402
- import { isValidDateRange } from "@northguild/gmt";
403
-
404
- isValidDateRange("2024-01-01", "2024-12-31"); // false — expects { value1, value2 }
405
- ```
406
-
407
- Correct:
408
-
409
- ```ts
410
- import { isValidDateInterval } from "@northguild/gmt";
411
-
412
- const valid = isValidDateInterval("2024-01-01", "2024-12-31"); // true
413
- ```
414
-
415
- Source: `plain/validate/isValidDateRange.ts` — range validators take `{ value1, value2, options? }`; interval validators take `(start, end)` positional args
416
-
417
- ### MEDIUM Assuming intervals accept reversed bounds
418
-
419
- Wrong:
420
-
421
- ```ts
422
- import { isValidDateInterval } from "@northguild/gmt";
423
-
424
- const valid = isValidDateInterval("2024-12-31", "2024-01-01"); // false — start must be <= end
425
- ```
426
-
427
- Correct:
428
-
429
- ```ts
430
- const valid = isValidDateInterval("2024-01-01", "2024-12-31"); // true
431
- ```
432
-
433
- Source: `plain/interval/validate/isValidDateInterval.ts` — interval validators enforce `start <= end`
434
-
435
- ## References
436
-
437
- - [Full validate API](references/validate-api.md)
438
- - [Temporal validation patterns](https://tc39.es/proposal-temporal/docs/iso.html)