@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.
- package/README.md +43 -13
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/plain/calculate/diffDateAsDuration.js +1 -1
- package/dist/plain/calculate/index.d.ts +2 -1
- package/dist/plain/calculate/index.js +2 -1
- package/dist/plain/calculate/{weekOfYear.d.ts → weekOfYearForDate.d.ts} +0 -14
- package/dist/plain/calculate/weekOfYearForDate.js +28 -0
- package/dist/plain/calculate/weekOfYearForDateTime.d.ts +14 -0
- package/dist/plain/calculate/{weekOfYear.js → weekOfYearForDateTime.js} +1 -27
- package/dist/plain/format/formatCalendar.d.ts +2 -2
- package/dist/plain/format/formatDate.d.ts +3 -2
- package/dist/plain/format/formatDate.js +1 -1
- package/dist/plain/format/formatDateRange.d.ts +3 -2
- package/dist/plain/format/formatDateRange.js +1 -1
- package/dist/plain/format/formatDateTime.d.ts +3 -2
- package/dist/plain/format/formatDateTime.js +1 -1
- package/dist/plain/format/formatDateTimeRange.d.ts +3 -2
- package/dist/plain/format/formatDateTimeRange.js +1 -1
- package/dist/plain/format/formatDateTimeToParts.d.ts +3 -2
- package/dist/plain/format/formatDateTimeToParts.js +1 -1
- package/dist/plain/format/formatDateToParts.d.ts +3 -2
- package/dist/plain/format/formatDateToParts.js +1 -1
- package/dist/plain/format/formatRelativeDate.d.ts +3 -14
- package/dist/plain/format/formatRelativeDateTime.d.ts +3 -14
- package/dist/plain/format/formatRelativeTime.d.ts +3 -14
- package/dist/plain/format/formatTime.d.ts +2 -1
- package/dist/plain/get/getNowUnit.d.ts +2 -3
- package/dist/plain/interval/splitIntervalByUnitDate.js +1 -1
- package/dist/regex/calendar-date.d.ts +19 -0
- package/dist/regex/calendar-date.js +19 -10
- package/dist/regex/calendar-zoned-date-time.d.ts +45 -0
- package/dist/regex/calendar-zoned-date-time.js +45 -40
- package/dist/regex/date-time.d.ts +18 -0
- package/dist/regex/date-time.js +18 -1
- package/dist/regex/date.d.ts +16 -0
- package/dist/regex/date.js +16 -1
- package/dist/regex/http-date.d.ts +15 -0
- package/dist/regex/http-date.js +15 -6
- package/dist/regex/leap-second.d.ts +12 -0
- package/dist/regex/leap-second.js +12 -1
- package/dist/regex/rfc-2822.d.ts +18 -0
- package/dist/regex/rfc-2822.js +18 -8
- package/dist/regex/rfc-3339.d.ts +19 -0
- package/dist/regex/rfc-3339.js +19 -6
- package/dist/regex/sql-date-time.d.ts +14 -0
- package/dist/regex/sql-date-time.js +14 -6
- package/dist/regex/time-zone-like.d.ts +21 -0
- package/dist/regex/time-zone-like.js +21 -0
- package/dist/regex/time.d.ts +59 -0
- package/dist/regex/time.js +59 -3
- package/dist/regex/unix.d.ts +21 -0
- package/dist/regex/unix.js +21 -0
- package/dist/regex/utc-date-time.d.ts +20 -0
- package/dist/regex/utc-date-time.js +20 -1
- package/dist/types/calendar-options.d.ts +11 -0
- package/dist/types/calendar-options.js +0 -0
- package/dist/types/datetime-format-options.d.ts +6 -0
- package/dist/types/datetime-format-options.js +0 -0
- package/dist/types/duration-unit.d.ts +5 -0
- package/dist/types/duration-unit.js +0 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/index.js +11 -0
- package/dist/types/now-unit.d.ts +5 -0
- package/dist/types/now-unit.js +0 -0
- package/dist/types/relative-date-time-unit.d.ts +6 -0
- package/dist/types/relative-date-time-unit.js +0 -0
- package/dist/types/relative-date-unit.d.ts +5 -0
- package/dist/types/relative-date-unit.js +0 -0
- package/dist/types/relative-time-options.d.ts +18 -0
- package/dist/types/relative-time-options.js +0 -0
- package/dist/types/relative-time-unit.d.ts +5 -0
- package/dist/types/relative-time-unit.js +0 -0
- package/dist/types/relative-unit.d.ts +6 -0
- package/dist/types/relative-unit.js +0 -0
- package/dist/types/unix-now-unit.d.ts +5 -0
- package/dist/types/unix-now-unit.js +0 -0
- package/dist/types/utc-now-unit.d.ts +5 -0
- package/dist/types/utc-now-unit.js +0 -0
- package/dist/unix/calculate/startOrEndOfUnix.d.ts +18 -0
- package/dist/unix/calculate/startOrEndOfUnix.js +18 -0
- package/dist/unix/format/formatCalendarUnix.d.ts +27 -1
- package/dist/unix/format/formatRelativeUnix.d.ts +1 -8
- package/dist/unix/format/formatUnix.d.ts +19 -0
- package/dist/unix/format/formatUnix.js +19 -0
- package/dist/unix/get/getUnixNowUnit.d.ts +2 -3
- package/dist/unix/parse/parseUnitFromUnix.d.ts +24 -0
- package/dist/unix/validate/isValidUnixUnit.d.ts +15 -0
- package/dist/utc/calculate/startOrEndOfUtc.d.ts +17 -0
- package/dist/utc/calculate/startOrEndOfUtc.js +17 -0
- package/dist/utc/format/formatCalendarUtc.d.ts +2 -2
- package/dist/utc/format/formatRelativeUtc.d.ts +2 -12
- package/dist/utc/format/formatUtc.d.ts +33 -0
- package/dist/utc/format/formatUtc.js +17 -0
- package/dist/utc/get/getUtcNowUnit.d.ts +2 -3
- package/dist/utc/parse/parseUnitFromUtc.d.ts +23 -0
- package/dist/zoned/format/formatRelativeZoned.d.ts +1 -8
- package/dist/zoned/format/formatTimeZoneName.d.ts +15 -0
- package/dist/zoned/format/formatZonedDateTime.d.ts +2 -1
- package/dist/zoned/format/formatZonedRange.d.ts +2 -1
- package/dist/zoned/format/formatZonedToParts.d.ts +2 -1
- package/dist/zoned/get/getDstTransitions.d.ts +18 -2
- package/dist/zoned/get/getZonedNowUnit.d.ts +24 -0
- package/dist/zoned/interval/intervalDifferenceZoned.d.ts +3 -3
- package/dist/zoned/interval/intervalDifferenceZoned.js +3 -3
- package/dist/zoned/interval/intervalXorZoned.d.ts +6 -4
- package/dist/zoned/interval/intervalXorZoned.js +6 -4
- package/dist/zoned/parse/getZonedOffsetAs.d.ts +11 -0
- package/dist/zoned/parse/parseUnitFromZoned.d.ts +24 -0
- package/package.json +25 -7
- package/skills/gmt-arithmetic/SKILL.md +83 -0
- package/skills/gmt-basics/SKILL.md +80 -0
- package/skills/gmt-integration/SKILL.md +73 -0
- package/skills/gmt-timezone/SKILL.md +80 -0
- package/skills/_artifacts/domain_map.yaml +0 -547
- package/skills/_artifacts/skill_spec.md +0 -67
- package/skills/_artifacts/skill_tree.yaml +0 -278
- package/skills/api-expansion-workflow/SKILL.md +0 -52
- package/skills/app-integration/SKILL.md +0 -38
- package/skills/calculate-dates/SKILL.md +0 -432
- package/skills/compare-dates/SKILL.md +0 -412
- package/skills/convert-types/SKILL.md +0 -305
- package/skills/durations/SKILL.md +0 -418
- package/skills/format-date-time/SKILL.md +0 -486
- package/skills/format-date-time/references/format-api.md +0 -34
- package/skills/format-relative-time/SKILL.md +0 -223
- package/skills/get-current/SKILL.md +0 -229
- package/skills/interval-ops/SKILL.md +0 -432
- package/skills/issue-creation/SKILL.md +0 -118
- package/skills/lint-package-suggestion/SKILL.md +0 -37
- package/skills/new-method-implementation/SKILL.md +0 -71
- package/skills/parse-date-time/SKILL.md +0 -349
- package/skills/pr-contribution/SKILL.md +0 -180
- package/skills/unit-test-generation/SKILL.md +0 -56
- package/skills/validate-dates/SKILL.md +0 -438
- package/skills/zoned-date-ops/SKILL.md +0 -422
- package/skills/zoned-date-ops/references/timezones.md +0 -13
|
@@ -1,486 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: format-date-time
|
|
3
|
-
description: >
|
|
4
|
-
Format plain date/time values for display with locale and Intl.DateTimeFormat
|
|
5
|
-
options. Use formatDate, formatTime, formatDateTime for absolute formatting;
|
|
6
|
-
formatDateRange, formatDateTimeRange for a locale-elided range between two
|
|
7
|
-
plain values; formatDateToParts, formatDateTimeToParts, formatZonedToParts for
|
|
8
|
-
locale-ordered { type, value } parts; formatRelativeDate, formatRelativeTime,
|
|
9
|
-
formatRelativeDateTime for human-friendly relative output ("yesterday", "in 2
|
|
10
|
-
hours"); formatCalendar, formatCalendarZoned, formatCalendarUnix,
|
|
11
|
-
formatCalendarUtc for a relative day label + time-of-day ("tomorrow at 2:30
|
|
12
|
-
PM") — distinct from the elapsed-time formatRelative* phrasing. Also
|
|
13
|
-
getLocaleEraNames, getLocaleMonthNames, getLocaleWeekdayNames,
|
|
14
|
-
getLocaleMeridiems for standalone locale calendar-name lookups (Luxon Info
|
|
15
|
-
equivalent). Also formatRfc2822, formatHttp, formatSql, formatRfc3339 for
|
|
16
|
-
fixed, non-locale interchange grammars (email/HTTP headers, SQL, RFC 3339) —
|
|
17
|
-
no locale argument.
|
|
18
|
-
sources:
|
|
19
|
-
- 'northguild/gmt:packages/gmt/src/plain/format/index.ts'
|
|
20
|
-
- 'northguild/gmt:packages/gmt/src/plain/format/formatDateRange.ts'
|
|
21
|
-
- 'northguild/gmt:packages/gmt/src/plain/format/formatDateTimeRange.ts'
|
|
22
|
-
- 'northguild/gmt:packages/gmt/src/zoned/format/formatZonedRange.ts'
|
|
23
|
-
- 'northguild/gmt:packages/gmt/src/plain/format/formatDateToParts.ts'
|
|
24
|
-
- 'northguild/gmt:packages/gmt/src/plain/format/formatDateTimeToParts.ts'
|
|
25
|
-
- 'northguild/gmt:packages/gmt/src/zoned/format/formatZonedToParts.ts'
|
|
26
|
-
- 'northguild/gmt:packages/gmt/src/plain/locale/index.ts'
|
|
27
|
-
- 'northguild/gmt:packages/gmt/src/plain/locale/getLocaleEraNames.ts'
|
|
28
|
-
- 'northguild/gmt:packages/gmt/src/plain/locale/getLocaleMonthNames.ts'
|
|
29
|
-
- 'northguild/gmt:packages/gmt/src/plain/locale/getLocaleWeekdayNames.ts'
|
|
30
|
-
- 'northguild/gmt:packages/gmt/src/plain/locale/getLocaleMeridiems.ts'
|
|
31
|
-
- 'northguild/gmt:packages/gmt/src/zoned/format/formatRfc2822.ts'
|
|
32
|
-
- 'northguild/gmt:packages/gmt/src/utc/format/formatHttp.ts'
|
|
33
|
-
- 'northguild/gmt:packages/gmt/src/plain/format/formatSql.ts'
|
|
34
|
-
- 'northguild/gmt:packages/gmt/src/zoned/format/formatRfc3339.ts'
|
|
35
|
-
- 'northguild/gmt:packages/gmt/src/plain/format/formatCalendar.ts'
|
|
36
|
-
- 'northguild/gmt:packages/gmt/src/zoned/format/formatCalendarZoned.ts'
|
|
37
|
-
- 'northguild/gmt:packages/gmt/src/unix/format/formatCalendarUnix.ts'
|
|
38
|
-
- 'northguild/gmt:packages/gmt/src/utc/format/formatCalendarUtc.ts'
|
|
39
|
-
- 'northguild/gmt:packages/gmt/src/internal/joinDateTimeConnector.ts'
|
|
40
|
-
metadata:
|
|
41
|
-
type: core
|
|
42
|
-
library: '@northguild/gmt'
|
|
43
|
-
library_version: '1.14.2'
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
# Format Date/Time
|
|
47
|
-
|
|
48
|
-
Use this skill when you need to format date or time values for display to users.
|
|
49
|
-
|
|
50
|
-
## Setup
|
|
51
|
-
|
|
52
|
-
```ts
|
|
53
|
-
import {
|
|
54
|
-
formatDate,
|
|
55
|
-
formatTime,
|
|
56
|
-
formatDateTime,
|
|
57
|
-
formatRelativeDate,
|
|
58
|
-
formatRelativeTime,
|
|
59
|
-
formatRelativeDateTime,
|
|
60
|
-
} from "@northguild/gmt";
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
## Core Patterns
|
|
64
|
-
|
|
65
|
-
### Format date with default locale
|
|
66
|
-
|
|
67
|
-
```ts
|
|
68
|
-
const formatted = formatDate("2024-03-15"); // "3/15/2024" (US format)
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Format date with specific locale
|
|
72
|
-
|
|
73
|
-
```ts
|
|
74
|
-
const usDate = formatDate("2024-03-15", "en-US"); // "3/15/2024"
|
|
75
|
-
const ukDate = formatDate("2024-03-15", "en-GB"); // "15/03/2024"
|
|
76
|
-
const deDate = formatDate("2024-03-15", "de-DE"); // "15.3.2024"
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### Format time with locale
|
|
80
|
-
|
|
81
|
-
```ts
|
|
82
|
-
const time = formatTime("14:30:45"); // "2:30:45 PM"
|
|
83
|
-
const timeUk = formatTime("14:30:45", "en-GB"); // "14:30:45"
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
### Format datetime with locale
|
|
87
|
-
|
|
88
|
-
```ts
|
|
89
|
-
const formatted = formatDateTime("2024-03-15T14:30:45"); // "3/15/2024, 2:30:45 PM"
|
|
90
|
-
const formattedUk = formatDateTime("2024-03-15T14:30:45", "en-GB"); // "15/03/2024, 14:30:45"
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Format with options
|
|
94
|
-
|
|
95
|
-
```ts
|
|
96
|
-
import { formatDate } from "@northguild/gmt";
|
|
97
|
-
|
|
98
|
-
const formatted = formatDate("2024-03-15", "en-US", {
|
|
99
|
-
year: "numeric",
|
|
100
|
-
month: "long",
|
|
101
|
-
day: "numeric"
|
|
102
|
-
}); // "March 15, 2024"
|
|
103
|
-
```
|
|
104
|
-
|
|
105
|
-
### Format a plain date/datetime range
|
|
106
|
-
|
|
107
|
-
```ts
|
|
108
|
-
import { formatDateRange, formatDateTimeRange } from "@northguild/gmt";
|
|
109
|
-
|
|
110
|
-
formatDateRange("2024-02-03", "2024-02-05", "en-US", { dateStyle: "long" });
|
|
111
|
-
// "February 3 – 5, 2024" — Intl elides the shared month/year automatically
|
|
112
|
-
|
|
113
|
-
formatDateRange("2024-11-03", "2025-02-10", "en-US", { dateStyle: "long" });
|
|
114
|
-
// "November 3, 2024 – February 10, 2025" — no elision once the year differs
|
|
115
|
-
|
|
116
|
-
formatDateTimeRange(
|
|
117
|
-
"2024-02-03T09:00:00",
|
|
118
|
-
"2024-02-03T17:00:00",
|
|
119
|
-
"en-US",
|
|
120
|
-
{ dateStyle: "long", timeStyle: "short" },
|
|
121
|
-
);
|
|
122
|
-
// "February 3, 2024, 9:00 AM – 5:00 PM" — same day collapses to one date
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
These are the plain (timezone-free) counterparts of `formatZonedRange` (zoned
|
|
126
|
-
namespace) — same parameter order (`start, end, locale?, options?`) and
|
|
127
|
-
option shape, wrapping `Intl.DateTimeFormat.prototype.formatRange` directly
|
|
128
|
-
instead of joining two separately-formatted strings by hand. Do not swap
|
|
129
|
-
`start`/`end` before calling — a reversed range still formats (it does not
|
|
130
|
-
throw or auto-correct), so validate ordering yourself if that matters to the
|
|
131
|
-
caller.
|
|
132
|
-
|
|
133
|
-
### Get locale-ordered parts instead of a finished string
|
|
134
|
-
|
|
135
|
-
```ts
|
|
136
|
-
import { formatDateToParts, formatDateTimeToParts } from "@northguild/gmt";
|
|
137
|
-
import { formatZonedToParts } from "@northguild/gmt";
|
|
138
|
-
|
|
139
|
-
formatDateToParts("2024-03-15", "en-US");
|
|
140
|
-
// [{ type: "month", value: "3" }, { type: "literal", value: "/" },
|
|
141
|
-
// { type: "day", value: "15" }, { type: "literal", value: "/" },
|
|
142
|
-
// { type: "year", value: "2024" }]
|
|
143
|
-
|
|
144
|
-
formatDateToParts("2024-03-15", "fr-FR");
|
|
145
|
-
// day comes before month — same locale-order guarantee formatDate gives you,
|
|
146
|
-
// but as parts you can restyle instead of a finished string.
|
|
147
|
-
// [{ type: "day", value: "15" }, { type: "literal", value: "/" },
|
|
148
|
-
// { type: "month", value: "3" }, { type: "literal", value: "/" },
|
|
149
|
-
// { type: "year", value: "2024" }]
|
|
150
|
-
|
|
151
|
-
formatZonedToParts(
|
|
152
|
-
"2024-03-15T14:30:00-04:00[America/New_York]",
|
|
153
|
-
"en-US",
|
|
154
|
-
{ timeZoneName: "longOffset" },
|
|
155
|
-
);
|
|
156
|
-
// includes { type: "timeZoneName", value: "GMT-4" }
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Iterate the returned array in order — do not pick out `.find(p => p.type === "month")` and reassemble parts into a fixed order, since that reintroduces the exact locale-ordering bug `formatToParts` exists to avoid (see Common Mistakes below).
|
|
160
|
-
|
|
161
|
-
### Format relative date
|
|
162
|
-
|
|
163
|
-
```ts
|
|
164
|
-
import { formatRelativeDate } from "@northguild/gmt";
|
|
165
|
-
|
|
166
|
-
const ref = "2024-03-15";
|
|
167
|
-
formatRelativeDate("2024-03-12", "en-US", { reference: ref }); // "3 days ago"
|
|
168
|
-
formatRelativeDate("2024-03-18", "en-US", { reference: ref }); // "in 3 days"
|
|
169
|
-
formatRelativeDate("2024-03-14", "en-US", { reference: ref }); // "yesterday"
|
|
170
|
-
formatRelativeDate("2023-03-15", "en-US", { reference: ref }); // "last year"
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
### Format relative time / datetime
|
|
174
|
-
|
|
175
|
-
```ts
|
|
176
|
-
import { formatRelativeTime, formatRelativeDateTime } from "@northguild/gmt";
|
|
177
|
-
|
|
178
|
-
formatRelativeTime("11:30:00", "en-US", { reference: "12:00:00" });
|
|
179
|
-
// "30 minutes ago"
|
|
180
|
-
|
|
181
|
-
formatRelativeDateTime("2024-03-15T10:00:00", "en-US", {
|
|
182
|
-
reference: "2024-03-15T12:00:00",
|
|
183
|
-
}); // "2 hours ago"
|
|
184
|
-
```
|
|
185
|
-
|
|
186
|
-
### Relative format options
|
|
187
|
-
|
|
188
|
-
- `reference: string` — required anchor (the same shape as `value`)
|
|
189
|
-
- `numeric: "auto" | "always"` — default `"auto"`. `"auto"` produces "yesterday"/"tomorrow"; `"always"` forces "1 day ago"/"in 1 day"
|
|
190
|
-
- `style: "long" | "short" | "narrow"` — default `"long"`
|
|
191
|
-
- `largestUnit` — override the auto-picked unit (e.g. `"week"` to force "3 weeks ago" instead of "last month")
|
|
192
|
-
|
|
193
|
-
### Format a relative day label + time-of-day (Moment's `.calendar()`)
|
|
194
|
-
|
|
195
|
-
```ts
|
|
196
|
-
import { formatCalendar, formatCalendarZoned } from "@northguild/gmt";
|
|
197
|
-
|
|
198
|
-
const ref = "2026-03-15T09:00:00";
|
|
199
|
-
formatCalendar("2026-03-16T14:30:00", "en-US", { reference: ref });
|
|
200
|
-
// "tomorrow at 2:30 PM"
|
|
201
|
-
|
|
202
|
-
formatCalendar("2026-03-15T14:30:00", "en-US", { reference: ref });
|
|
203
|
-
// "today at 2:30 PM"
|
|
204
|
-
|
|
205
|
-
formatCalendar("2026-03-08T14:30:00", "en-US", { reference: ref });
|
|
206
|
-
// "March 8, 2026 at 2:30 PM" — 7 days out, beyond the ±6-day threshold,
|
|
207
|
-
// falls back to an absolute date + time with no relative wording
|
|
208
|
-
|
|
209
|
-
formatCalendarZoned(
|
|
210
|
-
"2026-03-16T14:30:00-04:00[America/New_York]",
|
|
211
|
-
"de-DE",
|
|
212
|
-
{ reference: "2026-03-15T09:00:00-04:00[America/New_York]" },
|
|
213
|
-
);
|
|
214
|
-
// "morgen um 14:30" — the connector ("um") is the locale's own, read from
|
|
215
|
-
// Intl's combined date+time pattern, never a hardcoded "at"
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Unlike `formatRelativeDate`/`formatRelativeDateTime` (which auto-pick a unit
|
|
219
|
-
and always render an elapsed-time phrase — "in 1 day"), `formatCalendar*`
|
|
220
|
-
always renders a day-granularity label plus the time-of-day, and switches to
|
|
221
|
-
an absolute date beyond a fixed ±6-day threshold instead of degrading to
|
|
222
|
-
"in 9 days". Options: `reference` (default "now"), `timeStyle` ("short"
|
|
223
|
-
default, "medium", plus "full" on the zoned/unix/utc variants — not on plain
|
|
224
|
-
`formatCalendar`, since a plain value has no real timezone for "full"'s
|
|
225
|
-
`timeZoneName` to name; see its JSDoc).
|
|
226
|
-
|
|
227
|
-
### Standalone locale calendar names (no date value needed)
|
|
228
|
-
|
|
229
|
-
These return locale-formatted calendar names directly — the GMT equivalent of Luxon's `Info` class — without requiring a date value:
|
|
230
|
-
|
|
231
|
-
```ts
|
|
232
|
-
import {
|
|
233
|
-
getLocaleEraNames,
|
|
234
|
-
getLocaleMonthNames,
|
|
235
|
-
getLocaleWeekdayNames,
|
|
236
|
-
getLocaleMeridiems,
|
|
237
|
-
} from "@northguild/gmt";
|
|
238
|
-
|
|
239
|
-
getLocaleEraNames("en-US");
|
|
240
|
-
// ["Before Christ", "Anno Domini"]
|
|
241
|
-
|
|
242
|
-
getLocaleEraNames("ja-JP", "short");
|
|
243
|
-
// ["紀元前", "西暦"]
|
|
244
|
-
|
|
245
|
-
getLocaleMonthNames("en-US");
|
|
246
|
-
// ["January", "February", ... "December"]
|
|
247
|
-
|
|
248
|
-
getLocaleMonthNames("de-DE", "short");
|
|
249
|
-
// ["Jan", "Feb", "Mär", ... "Dez"]
|
|
250
|
-
|
|
251
|
-
getLocaleWeekdayNames("en-US");
|
|
252
|
-
// ["Sunday", "Monday", ... "Saturday"] (locale-first-day order)
|
|
253
|
-
|
|
254
|
-
getLocaleWeekdayNames("fr-FR");
|
|
255
|
-
// ["lundi", "mardi", ... "dimanche"]
|
|
256
|
-
|
|
257
|
-
getLocaleMeridiems("en-US");
|
|
258
|
-
// ["AM", "PM"]
|
|
259
|
-
|
|
260
|
-
getLocaleMeridiems("zh-CN");
|
|
261
|
-
// ["上午", "下午"]
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
Options:
|
|
265
|
-
|
|
266
|
-
- `getLocaleEraNames(locale, style?)` — 2-element `[BCE-label, CE-label]` Gregorian era names. `style: "long" | "short" | "narrow"` (default `"long"`).
|
|
267
|
-
- `getLocaleMonthNames(locale, style?)` — 12 Gregorian month names in calendar order. `style: "long" | "short" | "narrow"` (default `"long"`).
|
|
268
|
-
- `getLocaleWeekdayNames(locale, style?)` — 7 weekday names in the locale's **first-day order** (Sunday-first for en-US, Monday-first for fr-FR). This matches `getLocaleDayOfWeek`, where index 0 is the locale's first day of the week.
|
|
269
|
-
- `getLocaleMeridiems(locale)` — `[AM-label, PM-label]`; labels are locale-varying (e.g. `en-GB` → `["am","pm"]`, `sv-SE` → `["fm","em"]`, `zh-CN` → `["上午","下午"]`).
|
|
270
|
-
|
|
271
|
-
All four return `[]` for an invalid BCP 47 locale tag. If a locale has no distinct BCE/CE era names, `getLocaleEraNames` returns both elements as the same string — the sentinel is reserved for invalid input only.
|
|
272
|
-
|
|
273
|
-
### Named machine formats (email, HTTP, SQL, RFC 3339)
|
|
274
|
-
|
|
275
|
-
These are **fixed, non-locale-adaptive grammars** — RFC 5322/RFC 7231 mandate
|
|
276
|
-
English weekday/month abbreviations regardless of caller locale, by
|
|
277
|
-
specification. This does not contradict the token-formatter exclusion above
|
|
278
|
-
(Decision 1): there is no locale-appropriate alternative field order to lose,
|
|
279
|
-
because the grammar is a constant, not a display choice. None of these four
|
|
280
|
-
take a `locale` argument.
|
|
281
|
-
|
|
282
|
-
```ts
|
|
283
|
-
import { formatRfc2822, formatHttp, formatSql, formatRfc3339 } from "@northguild/gmt";
|
|
284
|
-
|
|
285
|
-
// Email `Date:` headers (RFC 5322 / RFC 2822) — zoned namespace.
|
|
286
|
-
formatRfc2822("2024-03-15T14:30:00-04:00[America/New_York]");
|
|
287
|
-
// "Fri, 15 Mar 2024 14:30:00 -0400"
|
|
288
|
-
|
|
289
|
-
// HTTP headers (RFC 7231 IMF-fixdate) — utc namespace, always GMT.
|
|
290
|
-
formatHttp("2024-03-15T14:30:00Z");
|
|
291
|
-
// "Fri, 15 Mar 2024 14:30:00 GMT"
|
|
292
|
-
|
|
293
|
-
// ANSI SQL / ODBC datetime literal — plain namespace, no time zone.
|
|
294
|
-
formatSql("2024-03-15T14:30:00");
|
|
295
|
-
// "2024-03-15 14:30:00"
|
|
296
|
-
|
|
297
|
-
// Strict RFC 3339 — zoned namespace; strips the bracketed IANA zone
|
|
298
|
-
// GMT's own zoned strings carry, which RFC 3339 does not permit.
|
|
299
|
-
formatRfc3339("2024-03-15T14:30:00-04:00[America/New_York]");
|
|
300
|
-
// "2024-03-15T14:30:00-04:00"
|
|
301
|
-
```
|
|
302
|
-
|
|
303
|
-
Each has a `parse*` counterpart in the `parse-date-time` skill.
|
|
304
|
-
|
|
305
|
-
## Locale Matrix and Runtime ICU data
|
|
306
|
-
|
|
307
|
-
See [Full format API](references/format-api.md) for the supported-locale
|
|
308
|
-
formatting matrix and how host ICU data (full vs. small-icu Node builds)
|
|
309
|
-
affects locale output.
|
|
310
|
-
|
|
311
|
-
## Common Mistakes
|
|
312
|
-
|
|
313
|
-
### HIGH Using Intl.DateTimeFormat directly
|
|
314
|
-
|
|
315
|
-
Wrong:
|
|
316
|
-
|
|
317
|
-
```ts
|
|
318
|
-
const formatted = new Intl.DateTimeFormat("en-US").format(new Date("2024-03-15"));
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
Correct:
|
|
322
|
-
|
|
323
|
-
```ts
|
|
324
|
-
import { formatDate } from "@northguild/gmt";
|
|
325
|
-
|
|
326
|
-
const formatted = formatDate("2024-03-15", "en-US");
|
|
327
|
-
```
|
|
328
|
-
|
|
329
|
-
Source: AGENTS.md — Never use JavaScript Date APIs
|
|
330
|
-
|
|
331
|
-
### MEDIUM Not handling empty string on invalid input
|
|
332
|
-
|
|
333
|
-
Wrong:
|
|
334
|
-
|
|
335
|
-
```ts
|
|
336
|
-
const formatted = formatDate("invalid-date");
|
|
337
|
-
// Assume formatted is always valid string
|
|
338
|
-
display(formatted);
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
Correct:
|
|
342
|
-
|
|
343
|
-
```ts
|
|
344
|
-
import { formatDate, isValidDate } from "@northguild/gmt";
|
|
345
|
-
|
|
346
|
-
const input = "invalid-date";
|
|
347
|
-
if (!isValidDate(input)) {
|
|
348
|
-
display("Invalid date");
|
|
349
|
-
} else {
|
|
350
|
-
display(formatDate(input));
|
|
351
|
-
}
|
|
352
|
-
```
|
|
353
|
-
|
|
354
|
-
Source: packages/gmt/src/plain/format/formatDate.ts — Returns "" on invalid input
|
|
355
|
-
|
|
356
|
-
### MEDIUM Assuming getLocale* throws or returns English for an invalid locale
|
|
357
|
-
|
|
358
|
-
Wrong:
|
|
359
|
-
|
|
360
|
-
```ts
|
|
361
|
-
const names = getLocaleMonthNames("not-a-locale");
|
|
362
|
-
// Assume names is non-empty or throws
|
|
363
|
-
render(names);
|
|
364
|
-
```
|
|
365
|
-
|
|
366
|
-
Correct:
|
|
367
|
-
|
|
368
|
-
```ts
|
|
369
|
-
import { getLocaleEraNames, getLocaleMonthNames } from "@northguild/gmt";
|
|
370
|
-
|
|
371
|
-
const names = getLocaleMonthNames("en-US");
|
|
372
|
-
const eras = getLocaleEraNames("en-US");
|
|
373
|
-
if (names.length === 0 || eras.length === 0) {
|
|
374
|
-
// invalid BCP 47 tag — fall back or surface an error
|
|
375
|
-
}
|
|
376
|
-
```
|
|
377
|
-
|
|
378
|
-
Source: packages/gmt/src/plain/locale/getLocaleMonthNames.ts — Returns [] for an invalid locale
|
|
379
|
-
|
|
380
|
-
### MEDIUM Looking for a token-pattern formatter (there isn't one, deliberately)
|
|
381
|
-
|
|
382
|
-
GMT has `parseDateWithPattern`/`parseDateTimeWithPattern`/`parseTimeWithPattern`
|
|
383
|
-
for *decoding* a string against a caller-supplied token pattern (e.g.
|
|
384
|
-
`"MM/dd/yyyy"`), but deliberately has no inverse token *formatter* for
|
|
385
|
-
producing output. This is not a gap to work around — it's roadmap Decision 1
|
|
386
|
-
(`context/roadmap/issues/J.md`): a hard-coded token pattern like
|
|
387
|
-
`"MM/dd/yyyy"` bakes in US field ordering (month before day) and ships it to
|
|
388
|
-
every locale, which is exactly the kind of locale bug GMT exists to prevent.
|
|
389
|
-
Parsing a *known, fixed* producer format is fine because there's no ambiguity
|
|
390
|
-
about what the input shape is; formatting *for output* by a fixed pattern
|
|
391
|
-
would impose that same fixed shape on every locale's display.
|
|
392
|
-
|
|
393
|
-
Wrong:
|
|
394
|
-
|
|
395
|
-
```ts
|
|
396
|
-
// There is no formatDateWithPattern — don't go looking for one, and don't
|
|
397
|
-
// hand-roll one by string-splitting/concatenating a formatted value into a
|
|
398
|
-
// fixed field order.
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
Correct:
|
|
402
|
-
|
|
403
|
-
```ts
|
|
404
|
-
import { formatDate } from "@northguild/gmt";
|
|
405
|
-
|
|
406
|
-
// Let Intl.DateTimeFormat pick field order per locale instead of a fixed
|
|
407
|
-
// pattern string.
|
|
408
|
-
formatDate("2024-03-15", "en-US"); // "3/15/2024"
|
|
409
|
-
formatDate("2024-03-15", "de-DE"); // "15.3.2024"
|
|
410
|
-
```
|
|
411
|
-
|
|
412
|
-
`formatDate`/`formatTime`/`formatDateTime` (locale-ordered strings) are the
|
|
413
|
-
current answer for display. For field-level output control (a custom layout
|
|
414
|
-
that still needs per-locale field order), use `formatDateToParts` /
|
|
415
|
-
`formatDateTimeToParts` / `formatZonedToParts` — GMT's substitute for a
|
|
416
|
-
token formatter (Story J12).
|
|
417
|
-
|
|
418
|
-
Source: context/roadmap/issues/J.md — Decision 1 (token formatter deliberately excluded); packages/gmt/src/plain/parse/parseDateWithPattern.ts — the parsing-only counterpart
|
|
419
|
-
|
|
420
|
-
### MEDIUM Reassembling `formatToParts` output in a fixed order
|
|
421
|
-
|
|
422
|
-
Wrong:
|
|
423
|
-
|
|
424
|
-
```ts
|
|
425
|
-
import { formatDateToParts } from "@northguild/gmt";
|
|
426
|
-
|
|
427
|
-
const parts = formatDateToParts("2024-03-15", locale);
|
|
428
|
-
const month = parts.find((p) => p.type === "month")?.value;
|
|
429
|
-
const day = parts.find((p) => p.type === "day")?.value;
|
|
430
|
-
const year = parts.find((p) => p.type === "year")?.value;
|
|
431
|
-
// Hard-codes US field order onto every locale — exactly the bug
|
|
432
|
-
// formatToParts exists to avoid.
|
|
433
|
-
const display = `${month}/${day}/${year}`;
|
|
434
|
-
```
|
|
435
|
-
|
|
436
|
-
Correct:
|
|
437
|
-
|
|
438
|
-
```ts
|
|
439
|
-
import { formatDateToParts } from "@northguild/gmt";
|
|
440
|
-
|
|
441
|
-
const parts = formatDateToParts("2024-03-15", locale);
|
|
442
|
-
const display = parts.map((p) => p.value).join("");
|
|
443
|
-
// Iterate as returned — the locale already ordered the parts. Restyle
|
|
444
|
-
// individual part values (e.g. wrap { type: "literal" } parts differently)
|
|
445
|
-
// without changing their relative order.
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
Source: context/roadmap/issues/J12 — "iterate the array as returned; reassembling parts in a fixed order reintroduces exactly the bug formatToParts exists to avoid"
|
|
449
|
-
|
|
450
|
-
### MEDIUM Confusing formatCalendar with formatRelativeDateTime
|
|
451
|
-
|
|
452
|
-
They answer different questions and are not interchangeable:
|
|
453
|
-
|
|
454
|
-
- `formatCalendar` (and its `formatCalendarZoned`/`formatCalendarUnix`/
|
|
455
|
-
`formatCalendarUtc` siblings) — "what should I show on a schedule/agenda
|
|
456
|
-
item?" → `"Tomorrow at 2:30 PM"`. Always includes the clock time; switches
|
|
457
|
-
to an absolute date beyond ±6 days.
|
|
458
|
-
- `formatRelativeDateTime` (and its `formatRelative*` siblings) — "how long
|
|
459
|
-
ago/from now was this?" → `"in 1 day"`. Never includes a clock time;
|
|
460
|
-
auto-picks the coarsest sensible unit (seconds through years) with no
|
|
461
|
-
distance threshold.
|
|
462
|
-
|
|
463
|
-
Wrong:
|
|
464
|
-
|
|
465
|
-
```ts
|
|
466
|
-
import { formatRelativeDateTime } from "@northguild/gmt";
|
|
467
|
-
|
|
468
|
-
// Building a meeting-list row and reaching for the relative formatter —
|
|
469
|
-
// it has no time-of-day in its output at all.
|
|
470
|
-
const row = formatRelativeDateTime(meeting.startsAt); // "in 1 day"
|
|
471
|
-
```
|
|
472
|
-
|
|
473
|
-
Correct:
|
|
474
|
-
|
|
475
|
-
```ts
|
|
476
|
-
import { formatCalendar } from "@northguild/gmt";
|
|
477
|
-
|
|
478
|
-
const row = formatCalendar(meeting.startsAt); // "tomorrow at 2:30 PM"
|
|
479
|
-
```
|
|
480
|
-
|
|
481
|
-
Source: context/roadmap/issues/J.md — J15's Common Mistakes requirement; packages/gmt/src/plain/format/formatCalendar.ts
|
|
482
|
-
|
|
483
|
-
## References
|
|
484
|
-
|
|
485
|
-
- [Full format API](references/format-api.md)
|
|
486
|
-
- [Intl.DateTimeFormat documentation](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/DateTimeFormat)
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
# Format API Reference
|
|
2
|
-
|
|
3
|
-
## Locale Matrix
|
|
4
|
-
|
|
5
|
-
Supported locales for formatting:
|
|
6
|
-
|
|
7
|
-
| Locale | Date Format | Time Format |
|
|
8
|
-
|--------|------------|-------------|
|
|
9
|
-
| en-US | 3/15/2024 | 2:30:45 PM |
|
|
10
|
-
| en-GB | 15/03/2024 | 14:30:45 |
|
|
11
|
-
| de-DE | 15.3.2024 | 14:30:45 |
|
|
12
|
-
| fr-FR | 15/03/2024 | 14:30:45 |
|
|
13
|
-
| es-ES | 15/3/2024 | 14:30:45 |
|
|
14
|
-
| it-IT | 15/03/2024 | 14:30:45 |
|
|
15
|
-
| pt-PT | 15/03/2024 | 14:30:45 |
|
|
16
|
-
| sv-SE | 2024-03-15 | 14:30:45 |
|
|
17
|
-
| is-IS | 15.3.2024 | 14:30:45 |
|
|
18
|
-
| zh-CN | 2024/3/15 | 下午2:30:45 |
|
|
19
|
-
| zh-TW | 2024/3/15 | 下午2:30:45 |
|
|
20
|
-
| ja-JP | 2024/3/15 | 14:30:45 |
|
|
21
|
-
| ko-KR | 2024. 3. 15. | 오후 2:30:45 |
|
|
22
|
-
| ar-SA | ١٥/٣/٢٠٢٤ | ٢:٣٠:٤٥ م |
|
|
23
|
-
| he-IL | 15/03/2024 | 14:30:45 |
|
|
24
|
-
| ru-RU | 15.03.2024 | 14:30:45 |
|
|
25
|
-
| tr-TR | 15.03.2024 | 14:30:45 |
|
|
26
|
-
|
|
27
|
-
## Runtime ICU data
|
|
28
|
-
|
|
29
|
-
These formatters delegate locale rendering to the host runtime's `Intl.DateTimeFormat` / `Intl.RelativeTimeFormat`. Output therefore depends on the ICU data shipped with the running Node (or browser):
|
|
30
|
-
|
|
31
|
-
- **Full ICU** runtimes (official Node binaries from nodejs.org, all modern browsers) return fully localized strings — e.g. `formatTime("14:30:00", "ko-KR", { timeStyle: "short" })` returns `"오후 2:30"`.
|
|
32
|
-
- **Small/partial ICU** runtimes (some Node builds compiled with `--with-intl=small-icu` or repackaged distributions) fall back to English day periods and other locale data — the same call may return `"PM 2:30"`.
|
|
33
|
-
|
|
34
|
-
This is a property of the runtime, not gmt. For consistent non-English output, deploy on a full-ICU Node build or polyfill `Intl` with a package that bundles locale data.
|