@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,305 +0,0 @@
1
- ---
2
- name: convert-types
3
- description: >
4
- Convert between temporal types, unix time, and UTC representations. Use
5
- convertPlainDateTimeToZoned (with optional disambiguation for DST gaps/
6
- overlaps), convertZonedToPlainDateTime, convertUtcToUnix, and
7
- convertDateToCalendar to express a date in a non-Gregorian CalendarSystem
8
- (gregorian, hebrew, islamic-civil, islamic-tabular, islamic-umalqura,
9
- japanese, buddhist, taiwan, persian, indian, ethiopic, ethiopic-amete-alem,
10
- coptic).
11
- sources:
12
- - 'northguild/gmt:packages/gmt/src/plain/convert/index.ts'
13
- - 'northguild/gmt:packages/gmt/src/zoned/convert/index.ts'
14
- - 'northguild/gmt:packages/gmt/src/unix/convert/index.ts'
15
- - 'northguild/gmt:packages/gmt/src/utc/convert/index.ts'
16
- - 'northguild/gmt:packages/gmt/src/types/calendar-system.ts'
17
- metadata:
18
- type: core
19
- library: '@northguild/gmt'
20
- library_version: '1.14.2'
21
- ---
22
-
23
- # Convert Temporal Types
24
-
25
- Use this skill when you need to convert between different temporal representations.
26
-
27
- ## Setup
28
-
29
- ```ts
30
- import { convertPlainDateTimeToZoned, convertZonedToPlainDateTime } from "@northguild/gmt/zoned";
31
- import { convertUtcToUnix, convertUnixToUtc } from "@northguild/gmt/unix";
32
- import { convertUtcToZoned, convertZonedToUtc } from "@northguild/gmt/utc";
33
- ```
34
-
35
- ## Core Patterns
36
-
37
- ### Convert plain to zoned datetime
38
-
39
- ```ts
40
- import { convertPlainDateTimeToZoned } from "@northguild/gmt/zoned";
41
-
42
- const zoned = convertPlainDateTimeToZoned("2024-03-15T14:30:45", "America/New_York");
43
- // "2024-03-15T14:30:45[America/New_York]"
44
- ```
45
-
46
- Twice a year, DST creates local times that don't exist (spring-forward gap) or happen twice (fall-back overlap). Pass `disambiguation` (`"compatible"` (default) | `"earlier"` | `"later"` | `"reject"`) to control resolution instead of silently guessing — see the [Zoned Date Operations skill](../zoned-date-ops/SKILL.md) for the full gap/overlap walkthrough:
47
-
48
- ```ts
49
- convertPlainDateTimeToZoned("2024-03-10T02:30:00", "America/New_York", {
50
- disambiguation: "reject",
51
- });
52
- // "" — 2024-03-10T02:30:00 doesn't exist in America/New_York (spring-forward gap)
53
- ```
54
-
55
- ### Convert zoned to plain datetime
56
-
57
- ```ts
58
- import { convertZonedToPlainDateTime } from "@northguild/gmt/zoned";
59
-
60
- const plain = convertZonedToPlainDateTime("2024-03-15T14:30:45[America/New_York]");
61
- // "2024-03-15T14:30:45"
62
- ```
63
-
64
- ### Convert UTC to Unix epoch (seconds)
65
-
66
- ```ts
67
- import { convertUtcToUnix } from "@northguild/gmt/unix";
68
-
69
- const unix = convertUtcToUnix("2024-03-15T14:30:45"); // 1710504645
70
- ```
71
-
72
- ### Convert Unix epoch to UTC (seconds)
73
-
74
- ```ts
75
- import { convertUnixToUtc } from "@northguild/gmt/unix";
76
-
77
- const utc = convertUnixToUtc(1710504645); // "2024-03-15T14:30:45"
78
- ```
79
-
80
- ### Convert UTC datetime to Unix milliseconds
81
-
82
- ```ts
83
- import { convertUtcToUnixMs } from "@northguild/gmt/unix";
84
-
85
- const unixMs = convertUtcToUnixMs("2024-03-15T14:30:45"); // 1710504645000
86
- ```
87
-
88
- ### Convert Unix milliseconds to UTC datetime
89
-
90
- ```ts
91
- import { convertUnixMsToUtc } from "@northguild/gmt/unix";
92
-
93
- const utc = convertUnixMsToUtc(1710504645000); // "2024-03-15T14:30:45"
94
- ```
95
-
96
- ### Convert zoned to UTC
97
-
98
- ```ts
99
- import { convertZonedToUtc } from "@northguild/gmt/zoned";
100
-
101
- const utc = convertZonedToUtc("2024-03-15T14:30:45[America/New_York]"); // "2024-03-15T19:30:45"
102
- ```
103
-
104
- ### Convert UTC to zoned
105
-
106
- ```ts
107
- import { convertUtcToZoned } from "@northguild/gmt/utc";
108
-
109
- const zoned = convertUtcToZoned("2024-03-15T14:30:45", "America/New_York"); // "2024-03-15T10:30:45[America/New_York]"
110
- ```
111
-
112
- ### Convert between timezones
113
-
114
- ```ts
115
- import { convertZonedToZoned } from "@northguild/gmt/zoned";
116
-
117
- const converted = convertZonedToZoned(
118
- "2024-03-15T14:30:45[America/New_York]",
119
- "Europe/London"
120
- ); // "2024-03-15T18:30:45[Europe/London]"
121
- ```
122
-
123
- ### Convert a date to a non-Gregorian calendar system
124
-
125
- ```ts
126
- import { convertDateToCalendar } from "@northguild/gmt/plain";
127
-
128
- const hebrew = convertDateToCalendar("2024-10-03", "hebrew");
129
- // "5785-01-01[u-ca=hebrew]" — Rosh Hashanah 5785, calendar-native year/month/day
130
-
131
- const back = convertDateToCalendar(hebrew, "gregorian");
132
- // "2024-10-03" — round-trips back to a bare ISO string
133
-
134
- const umalqura = convertDateToCalendar("2024-10-03", "islamic-umalqura");
135
- // "1446-03-30[u-ca=islamic-umalqura]" — Saudi civil calendar
136
-
137
- const buddhist = convertDateToCalendar("2024-10-03", "buddhist");
138
- // "2567-10-03[u-ca=buddhist]" — fixed +543 year offset
139
-
140
- const japanese = convertDateToCalendar("2024-10-03", "japanese");
141
- // "0006-10-03[u-ca=japanese;era=reiwa]" — era-relative year, not proleptic 2024
142
-
143
- const ethiopic = convertDateToCalendar("2024-10-03", "ethiopic");
144
- // "2017-01-23[u-ca=ethiopic;era=ethiopic]" — era-relative year, not proleptic 7517
145
-
146
- const coptic = convertDateToCalendar("2024-10-03", "coptic");
147
- // "1741-01-23[u-ca=coptic]" — 13-month structure, own epoch (AD 284)
148
- ```
149
-
150
- `CalendarSystem` is `"gregorian" | "hebrew" | "islamic-civil" | "islamic-tabular" | "islamic-umalqura" | "japanese" | "buddhist" | "taiwan" | "persian" | "indian" | "ethiopic" | "ethiopic-amete-alem" | "coptic"` today (extended by later Story Group E stories). The annotated string carries the target calendar's own year/month/day — not the ISO/Gregorian digits Temporal's own `[u-ca=...]` string convention keeps — so a Hebrew year like 5785 is visible directly in the string. A plain, unannotated string is always the `"gregorian"` calendar and works with every other GMT function unchanged.
151
-
152
- Every calendar except the Ethiopic family (below) is resolved through Temporal's own built-in calendar support (`PlainDate.prototype.withCalendar`) — GMT ports no leap-year tables or arithmetic of its own, for Islamic or era-based solar calendars any more than for Hebrew. The three Islamic variants are **not interchangeable**: `"islamic-civil"` and `"islamic-tabular"` use different fixed leap-year cycles one day apart in epoch, and `"islamic-umalqura"` is a tabulated calendar (the Saudi civil calendar) that can diverge from both by more than a fixed offset on a given date — `convertDateToCalendar` never approximates one variant with another's math. Note that GMT's own id for the tabular variant, `"islamic-tabular"`, differs from Temporal's internal id for the same calendar (`"islamic-tbla"`); the annotated string always reads `[u-ca=islamic-tabular]` regardless.
153
-
154
- `"buddhist"` and `"taiwan"` are fixed year-offset calendars over the same Gregorian day/month structure (`+543`, and reset-at-1912 respectively); `"persian"` and `"indian"` are distinct solar calendars with their own leap-year rules (Persian: a 33-year cycle; Indian: aligned to the Gregorian leap-year rule, not an independent one). `"japanese"` is the odd one out: Temporal's `.year` for it stays **proleptic** across imperial era changes rather than resetting the way the calendar's own numbering does, so `convertDateToCalendar` tags it with `.eraYear` and an era name instead of a plain year — `"0006-10-03[u-ca=japanese;era=reiwa]"`, not `"2024-10-03[u-ca=japanese]"`. GMT also does not reject pre-Meiji (before 1868-10-23) dates the way `@internationalized/date` does — Temporal resolves them under a synthetic `"japanese"` era and GMT passes that through rather than adding validation just to reproduce another library's gap.
155
-
156
- `"ethiopic"`, `"ethiopic-amete-alem"`, and `"coptic"` share one 13-month structure (12 x 30-day months + a 5/6-day Pagume/Nasie 13th month) but differ in epoch, and are the **one exception** to "resolved through Temporal's native calendar support": `@js-temporal/polyfill` resolves these two calendars' year/era via `Intl.DateTimeFormat`-derived era-name matching, and that matching breaks under newer ICU versions (confirmed: every read/write of Temporal's `"ethiopic"`/`"coptic"` calendar ids throws under ICU >= 78 — the ICU version both Node 22 and Node 24 bundle; this is an ICU-version boundary, not a Node-major one). GMT routes around this by reading/writing them through Temporal's `"ethioaa"` id instead (pure arithmetic, no era, unaffected by the bug — month/day are identical across the whole family) and computing each calendar's own year/era with GMT-owned arithmetic. `"ethiopic"` is era-based like `"japanese"` (resets at its own epoch, ~AD 8): `"2017-01-23[u-ca=ethiopic;era=ethiopic]"`, not a 5-digit proleptic year. `"ethiopic-amete-alem"` is the same calendar counted continuously from a much older epoch (~5493 BCE) and never resets: `"7517-01-23[u-ca=ethiopic-amete-alem]"` for the same date. `"coptic"` has its own epoch (AD 284, the Diocletian/Martyrs era) and a plain native year. See `internal/ethiopicFamilyCalendar.ts` for the implementation and full rationale.
157
-
158
- **The annotated string this function produces feeds directly into calendar-aware arithmetic (E5, issue #78):** `addDate`/`subtractDate`/`diffDate`/`diffDateAsDuration`, every `Date`-suffixed `plain/interval/*` function, and `duration/`'s `relativeTo` option all accept it — see the `calculate-dates`, `interval-ops`, and `durations` skills for how each resolves calendar-unit arithmetic in the value's own calendar. `zoned/`, `utc/`, and `unix/` reject it outright; there is no calendar-annotated `PlainDateTime`/`ZonedDateTime` grammar.
159
-
160
- ## Calendar Conversion
161
-
162
- - `convertDateToCalendar(value, calendar)` — PlainDate in any of the 13 calendar systems, e.g.
163
- `"5785-01-01[u-ca=hebrew]"`.
164
- - `convertZonedToCalendar(value, calendar)` — the zoned equivalent, keeping the instant, offset
165
- and IANA zone unchanged:
166
- `"5785-01-01T14:30:45-04:00[u-ca=hebrew][America/New_York]"`.
167
-
168
- Both chain: pass either function's output back in with a different target calendar. Converting to
169
- `"gregorian"` returns a bare, unannotated ISO string.
170
-
171
- Do **not** try to bridge between them by string surgery — a calendar-annotated `PlainDate` is not
172
- a valid input to any zoned conversion, and a calendar-annotated zoned string is not a valid
173
- `PlainDate`. Convert the value in its own namespace.
174
-
175
- ## Common Mistakes
176
-
177
- ### Building a calendar-annotated zoned string by hand
178
-
179
- GMT's zoned calendar grammar puts `[u-ca=...]` **before** `[timeZone]` — the reverse of RFC 9557
180
- and of Temporal's own `toString()`:
181
-
182
- ```
183
- 5784-06-15T14:30:00-05:00[u-ca=hebrew][America/New_York] // correct
184
- 5784-06-15T14:30:00-05:00[America/New_York][u-ca=hebrew] // WRONG — silently misparses in Temporal
185
- ```
186
-
187
- Always produce these with `convertZonedToCalendar`, never by concatenation. See the
188
- `zoned-date-ops` skill's Common Mistakes for the full trap.
189
-
190
- ### HIGH Using Date.getTime() for conversion
191
-
192
- Wrong:
193
-
194
- ```ts
195
- const unix = new Date("2024-03-15T14:30:45").getTime() / 1000; // manual conversion
196
- ```
197
-
198
- Correct:
199
-
200
- ```ts
201
- import { convertUtcToUnix } from "@northguild/gmt/unix";
202
-
203
- const unix = convertUtcToUnix("2024-03-15T14:30:45"); // proper conversion
204
- ```
205
-
206
- Source: AGENTS.md — Never use Date APIs
207
-
208
- ### HIGH Mixing epoch seconds and milliseconds
209
-
210
- Wrong:
211
-
212
- ```ts
213
- const timestamp = 1710504645; // seconds
214
- new Date(timestamp); // treats as milliseconds, wrong date
215
- ```
216
-
217
- Correct:
218
-
219
- ```ts
220
- import { convertUnixToUtc } from "@northguild/gmt/unix";
221
-
222
- const timestamp = 1710504645; // seconds
223
- const utc = convertUnixToUtc(timestamp);
224
- ```
225
-
226
- Source: packages/gmt/src/unix/convert/convertUnixToUtc.ts — expects seconds
227
-
228
- ### MEDIUM Not handling conversion errors
229
-
230
- Wrong:
231
-
232
- ```ts
233
- const zoned = convertPlainDateTimeToZoned("invalid", "America/New_York");
234
- // Assume zoned is always valid
235
- process(zoned);
236
- ```
237
-
238
- Correct:
239
-
240
- ```ts
241
- import { convertPlainDateTimeToZoned, isValidTimeZone } from "@northguild/gmt/zoned";
242
-
243
- if (!isValidTimeZone("America/New_York")) {
244
- throw new Error("Invalid timezone");
245
- }
246
- const zoned = convertPlainDateTimeToZoned("2024-03-15T14:30:45", "America/New_York");
247
- if (!zoned) {
248
- throw new Error("Conversion failed");
249
- }
250
- ```
251
-
252
- Source: packages/gmt/src/zoned/convert/convertPlainDateTimeToZoned.ts — Returns "" on error
253
-
254
- ### MEDIUM Assuming a `[u-ca=...]` string means Temporal's own convention
255
-
256
- Wrong:
257
-
258
- ```ts
259
- // Assuming the digits are still the ISO/Gregorian year, like Temporal.PlainDate's own
260
- // toString() would produce
261
- const hebrew = convertDateToCalendar("2024-10-03", "hebrew"); // "5785-01-01[u-ca=hebrew]"
262
- const year = hebrew.slice(0, 4); // "5785" is the Hebrew year, NOT 2024 — don't assume ISO digits
263
- ```
264
-
265
- Correct: treat the annotated string as GMT's own format (calendar-native fields, produced/consumed only by `convertDateToCalendar`) — never hand-parse it or assume it matches `Temporal.PlainDate.prototype.toString()`'s own `[u-ca=...]` output, which keeps the ISO digits and only tags the calendar. Round-trip it through `convertDateToCalendar` itself instead of extracting fields manually.
266
-
267
- Source: packages/gmt/src/plain/convert/convertDateToCalendar.ts — see JSDoc for the full rationale
268
-
269
- ### MEDIUM Assuming `"japanese"`'s annotated year is proleptic like every other calendar
270
-
271
- Wrong:
272
-
273
- ```ts
274
- // Assuming the year digits are the ISO/Gregorian year, the way "buddhist"/"taiwan"'s
275
- // digits are always a fixed transform of it
276
- const japanese = convertDateToCalendar("2024-10-03", "japanese");
277
- // "0006-10-03[u-ca=japanese;era=reiwa]" — "0006" is year 6 of the Reiwa era, NOT 2024
278
- const gregorianGuess = 2024 - Number(japanese.slice(0, 4)); // wrong: not how eras work
279
- ```
280
-
281
- Correct: `"japanese"` (and, separately, `"ethiopic"` — see below) is tagged with an era-relative `eraYear` plus an `;era=<name>` tag instead of a plain native year — Temporal's own `.year` for this calendar stays proleptic across era changes, so a plain year would silently misrepresent it. Round-trip through `convertDateToCalendar(value, "gregorian")` instead of computing the ISO year by hand.
282
-
283
- Source: packages/gmt/src/internal/calendarDateString.ts — see JSDoc for why "japanese" is tagged differently
284
-
285
- ### MEDIUM Assuming `"ethiopic"`'s annotated year is a fixed offset like `"ethiopic-amete-alem"`/`"coptic"`
286
-
287
- Wrong:
288
-
289
- ```ts
290
- // Assuming "ethiopic" digits are a fixed transform of the ISO year, the way its siblings'
291
- // digits are
292
- const ethiopic = convertDateToCalendar("2024-10-03", "ethiopic");
293
- // "2017-01-23[u-ca=ethiopic;era=ethiopic]" — "2017" is era-relative, not a fixed offset
294
- const wrongGuess = Number(ethiopic.slice(0, 4)) + 5500; // wrong once the era switches
295
- ```
296
-
297
- Correct: `"ethiopic"` resets to a new era (Amete Mihret) at its own epoch (~AD 8) and is tagged with `eraYear` + `;era=<name>`, exactly like `"japanese"`. `"ethiopic-amete-alem"` is the same calendar counted continuously with no era reset, so its year _is_ a fixed +5500ish transform of `"ethiopic"`'s eraYear — but only once you're past the era boundary. Round-trip through `convertDateToCalendar(value, "gregorian")` rather than computing it by hand.
298
-
299
- Source: packages/gmt/src/internal/ethiopicFamilyCalendar.ts — also documents why this family is computed with GMT-owned arithmetic instead of Temporal's native `"ethiopic"`/`"coptic"` calendar ids (an ICU-version compatibility bug in `@js-temporal/polyfill`)
300
-
301
- ## References
302
-
303
- - [Full convert API](references/convert-api.md)
304
- - [Unix epoch wikipedia](https://en.wikipedia.org/wiki/Unix_time)
305
- - [IANA timezone database](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)