@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,412 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: compare-dates
|
|
3
|
-
description: >
|
|
4
|
-
Compare date values for ordering. Use isAfterDate, isBeforeDate, areDatesEqual
|
|
5
|
-
for comparisons. Use areDatesEqualBy/areDateTimesEqualBy/areZonedEqualBy/
|
|
6
|
-
areUnixEqualBy/areUtcEqualBy to compare two values at a given calendar unit
|
|
7
|
-
("same month?"). Use isWeekend/isZonedWeekend for locale-aware weekend checks
|
|
8
|
-
(weekend days vary by locale). Use isBusinessDay for fixed ISO Mon-Fri checks
|
|
9
|
-
(locale-agnostic, matches addBusinessDays). Use
|
|
10
|
-
getLocaleDayOfWeek/getLocaleZonedDayOfWeek for a locale-relative day-of-week
|
|
11
|
-
index (0 = first day of week). Use isRelativeDay/isThisUnit/isPast/isFuture
|
|
12
|
-
(plus isZoned* variants) for now-relative predicates ("is this today", "is
|
|
13
|
-
this overdue") — depend on system clock/timeZone unless using the zoned
|
|
14
|
-
variants with an explicit timeZone. Use nextWeekday/previousWeekday for the
|
|
15
|
-
next/previous occurrence of an ISO day of week ("next Friday"). Returns
|
|
16
|
-
false/null/"" on invalid input.
|
|
17
|
-
sources:
|
|
18
|
-
- 'northguild/gmt:packages/gmt/src/plain/compare/index.ts'
|
|
19
|
-
- 'northguild/gmt:packages/gmt/src/zoned/compare/index.ts'
|
|
20
|
-
- 'northguild/gmt:packages/gmt/src/unix/compare/index.ts'
|
|
21
|
-
- 'northguild/gmt:packages/gmt/src/utc/compare/index.ts'
|
|
22
|
-
- 'northguild/gmt:packages/gmt/src/plain/calculate/getLocaleDayOfWeek.ts'
|
|
23
|
-
- 'northguild/gmt:packages/gmt/src/zoned/calculate/getLocaleZonedDayOfWeek.ts'
|
|
24
|
-
- 'northguild/gmt:packages/gmt/src/plain/calculate/nextWeekday.ts'
|
|
25
|
-
- 'northguild/gmt:packages/gmt/src/plain/calculate/previousWeekday.ts'
|
|
26
|
-
metadata:
|
|
27
|
-
type: core
|
|
28
|
-
library: '@northguild/gmt'
|
|
29
|
-
library_version: '1.14.2'
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
# Compare Dates
|
|
33
|
-
|
|
34
|
-
Use this skill when you need to compare date values for ordering.
|
|
35
|
-
|
|
36
|
-
## Setup
|
|
37
|
-
|
|
38
|
-
```ts
|
|
39
|
-
import { isAfterDate, isBeforeDate, areDatesEqual } from "@northguild/gmt";
|
|
40
|
-
import { isBetweenDate } from "@northguild/gmt";
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Core Patterns
|
|
44
|
-
|
|
45
|
-
### Check if date is after another
|
|
46
|
-
|
|
47
|
-
```ts
|
|
48
|
-
const result = isAfterDate("2024-03-20", "2024-03-15"); // true
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Check if date is before another
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
const result = isBeforeDate("2024-03-10", "2024-03-15"); // true
|
|
55
|
-
```
|
|
56
|
-
|
|
57
|
-
### Check if dates are equal
|
|
58
|
-
|
|
59
|
-
```ts
|
|
60
|
-
import { areDatesEqual } from "@northguild/gmt";
|
|
61
|
-
|
|
62
|
-
const result = areDatesEqual("2024-03-15", "2024-03-15"); // true
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
### Check if two values are equal at a given unit (same month, same year, ...)
|
|
66
|
-
|
|
67
|
-
```ts
|
|
68
|
-
import { areDatesEqualBy } from "@northguild/gmt";
|
|
69
|
-
|
|
70
|
-
areDatesEqualBy("2024-03-15", "2024-03-20", "month"); // true
|
|
71
|
-
areDatesEqualBy("2023-03-15", "2024-03-15", "month"); // false — same month, different year
|
|
72
|
-
areDatesEqualBy("2024-03-11", "2024-03-17", "week"); // true (default weekStartsOn: "monday")
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
`areDatesEqualBy`/`areDateTimesEqualBy`/`areZonedEqualBy`/`areUnixEqualBy`/`areUtcEqualBy` are the namespace variants of this pattern (Decision 5 — one parameterized function per namespace instead of a `isSameDay`/`isSameMonth`/`isSameYear`/... family). Equality is measured by comparing the *start of that unit* for each value, so a coarser unit like `"month"` implicitly requires every unit above it (year) to match too — see the Common Mistakes entry below. `areZonedEqualBy` compares each value's own local calendar fields (its own time zone), not the underlying instant.
|
|
76
|
-
|
|
77
|
-
Migrating from date-fns:
|
|
78
|
-
|
|
79
|
-
| date-fns | GMT |
|
|
80
|
-
| ----------------------------- | ------------------------------------- |
|
|
81
|
-
| `isSameDay(a, b)` | `areDatesEqualBy(a, b, "day")` |
|
|
82
|
-
| `isSameWeek(a, b, opts)` | `areDatesEqualBy(a, b, "week", opts)` |
|
|
83
|
-
| `isSameMonth(a, b)` | `areDatesEqualBy(a, b, "month")` |
|
|
84
|
-
| `isSameYear(a, b)` | `areDatesEqualBy(a, b, "year")` |
|
|
85
|
-
| `isSameHour(a, b)` | `areDateTimesEqualBy(a, b, "hour")` |
|
|
86
|
-
| `isSameMinute(a, b)` | `areDateTimesEqualBy(a, b, "minute")` |
|
|
87
|
-
| `isSameSecond(a, b)` | `areDateTimesEqualBy(a, b, "second")` |
|
|
88
|
-
|
|
89
|
-
### Check if date is between two dates
|
|
90
|
-
|
|
91
|
-
```ts
|
|
92
|
-
import { isBetweenDate } from "@northguild/gmt";
|
|
93
|
-
|
|
94
|
-
const result = isBetweenDate("2024-03-15", "2024-03-10", "2024-03-20"); // true
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
### Compare datetime values
|
|
98
|
-
|
|
99
|
-
```ts
|
|
100
|
-
import { isAfterDateTime, isBeforeDateTime, areDateTimesEqual } from "@northguild/gmt";
|
|
101
|
-
|
|
102
|
-
const after = isAfterDateTime("2024-03-15T14:30:45", "2024-03-15T14:30:00"); // true
|
|
103
|
-
const before = isBeforeDateTime("2024-03-15T14:30:00", "2024-03-15T14:30:45"); // true
|
|
104
|
-
const equal = areDateTimesEqual("2024-03-15T14:30:45", "2024-03-15T14:30:45"); // true
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### Compare time values
|
|
108
|
-
|
|
109
|
-
```ts
|
|
110
|
-
import { isAfterTime, isBeforeTime, areTimesEqual } from "@northguild/gmt";
|
|
111
|
-
|
|
112
|
-
const after = isAfterTime("14:30:45", "14:30:00"); // true
|
|
113
|
-
const before = isBeforeTime("14:30:00", "14:30:45"); // true
|
|
114
|
-
const equal = areTimesEqual("14:30:45", "14:30:45"); // true
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
### Check if a date falls on a weekend (locale-aware)
|
|
118
|
-
|
|
119
|
-
```ts
|
|
120
|
-
import { isWeekend, isZonedWeekend } from "@northguild/gmt";
|
|
121
|
-
|
|
122
|
-
isWeekend("2024-02-03", "en-US"); // true (Saturday, en-US weekend is Sat/Sun)
|
|
123
|
-
isWeekend("2024-02-02", "he-IL"); // true (Friday, he-IL weekend is Fri/Sat)
|
|
124
|
-
|
|
125
|
-
isZonedWeekend("2024-02-04T10:00:00+02:00[Asia/Jerusalem]", "he-IL"); // false (Sunday isn't part of he-IL's weekend)
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
`isZonedWeekend` checks the `ZonedDateTime`'s own local calendar day — no separate timezone conversion needed.
|
|
129
|
-
|
|
130
|
-
### Check if a date is a business day (fixed Mon–Fri)
|
|
131
|
-
|
|
132
|
-
```ts
|
|
133
|
-
import { isBusinessDay } from "@northguild/gmt";
|
|
134
|
-
|
|
135
|
-
isBusinessDay("2024-02-05"); // true (Monday)
|
|
136
|
-
isBusinessDay("2024-02-10"); // false (Saturday)
|
|
137
|
-
isBusinessDay("2024-02-04"); // false (Sunday)
|
|
138
|
-
```
|
|
139
|
-
|
|
140
|
-
`isBusinessDay` uses the fixed ISO Monday–Friday boundary (Mon=1 … Fri=5) — locale-agnostic and with no holiday calendar. It matches the boundary that `addBusinessDays`/`subtractBusinessDays` use, and is the locale-agnostic complement to `isWeekend` (which resolves weekend days per locale via `Intl.Locale`'s `weekInfo`).
|
|
141
|
-
|
|
142
|
-
### Get the locale-relative day-of-week index
|
|
143
|
-
|
|
144
|
-
```ts
|
|
145
|
-
import { getLocaleDayOfWeek, getLocaleZonedDayOfWeek } from "@northguild/gmt";
|
|
146
|
-
|
|
147
|
-
getLocaleDayOfWeek("2024-02-25", "en-US"); // 0 (Sunday = first day of en-US week)
|
|
148
|
-
getLocaleDayOfWeek("2024-02-26", "en-US"); // 1 (Monday)
|
|
149
|
-
getLocaleDayOfWeek("2024-02-26", "fr-FR"); // 0 (Monday = first day of fr-FR week)
|
|
150
|
-
getLocaleDayOfWeek("2024-02-24", "he-IL"); // 0 (Saturday = first day of he-IL week)
|
|
151
|
-
|
|
152
|
-
getLocaleZonedDayOfWeek("2024-02-25T12:00:00+00:00[UTC]", "en-US"); // 0
|
|
153
|
-
getLocaleZonedDayOfWeek("2024-02-26T12:00:00+00:00[UTC]", "fr-FR"); // 0
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
`getLocaleDayOfWeek` returns `null` on invalid input. `getLocaleZonedDayOfWeek` reads the `ZonedDateTime`'s local calendar day — no separate timezone conversion needed.
|
|
157
|
-
|
|
158
|
-
### Check now-relative predicates (today, this month, past, future)
|
|
159
|
-
|
|
160
|
-
```ts
|
|
161
|
-
import { isRelativeDay, isThisUnit, isPast, isFuture } from "@northguild/gmt";
|
|
162
|
-
|
|
163
|
-
isRelativeDay("2024-03-15", 0); // "is today" — true if today is 2024-03-15
|
|
164
|
-
isRelativeDay("2024-03-14", -1); // "is yesterday" — true if today is 2024-03-15
|
|
165
|
-
isRelativeDay("2024-03-16", 1); // "is tomorrow" — true if today is 2024-03-15
|
|
166
|
-
|
|
167
|
-
isThisUnit("2024-03-15", "month"); // true if today is any day in March 2024
|
|
168
|
-
isThisUnit("2024-02-26", "week", "fr-FR"); // locale-aware week boundary (fr-FR starts Monday)
|
|
169
|
-
|
|
170
|
-
isPast("2024-03-14"); // true if today is 2024-03-15 (strictly before, not on-or-before)
|
|
171
|
-
isFuture("2024-03-16"); // true if today is 2024-03-15 (strictly after, not on-or-before)
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
`isRelativeDay` subsumes `isToday`/`isYesterday`/`isTomorrow` (`offsetDays: 0`/`-1`/`1`); `isThisUnit` subsumes `isThisWeek`/`isThisMonth`/`isThisYear` (Decision 5, `context/roadmap/issues/J.md`). All four compare against `getToday()`, so they depend on the **system clock and system timeZone** — see the Common Mistakes entry below before using these in a server or test context.
|
|
175
|
-
|
|
176
|
-
Zoned counterparts — `isZonedRelativeDay`, `isZonedThisUnit`, `isZonedPast`, `isZonedFuture` — take a `ZonedDateTime` string and resolve "today"/"now" in *that value's own* timeZone, making them deterministic regardless of the host's system timeZone:
|
|
177
|
-
|
|
178
|
-
```ts
|
|
179
|
-
import { isZonedRelativeDay, isZonedThisUnit, isZonedPast, isZonedFuture } from "@northguild/gmt";
|
|
180
|
-
|
|
181
|
-
isZonedRelativeDay("2024-03-15T10:00:00-04:00[America/New_York]", 0); // "today" in America/New_York, not the host's timeZone
|
|
182
|
-
isZonedThisUnit("2024-03-15T10:00:00-04:00[America/New_York]", "month");
|
|
183
|
-
|
|
184
|
-
// isZonedPast/isZonedFuture compare the exact instant (not just the calendar
|
|
185
|
-
// day) against Temporal.Now.instant() — the zoned counterpart carries a
|
|
186
|
-
// full time-of-day, unlike the plain, day-only isPast/isFuture.
|
|
187
|
-
isZonedPast("2020-01-01T00:00:00Z[UTC]"); // true
|
|
188
|
-
isZonedFuture("2999-01-01T00:00:00Z[UTC]"); // true
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
### Find the next/previous occurrence of a weekday
|
|
192
|
-
|
|
193
|
-
```ts
|
|
194
|
-
import { nextWeekday, previousWeekday } from "@northguild/gmt";
|
|
195
|
-
|
|
196
|
-
nextWeekday("2024-03-13", 5); // "2024-03-15" (Wednesday -> next Friday)
|
|
197
|
-
nextWeekday("2024-03-15", 5); // "2024-03-22" (already Friday -> advances a full week by default)
|
|
198
|
-
nextWeekday("2024-03-15", 5, { inclusive: true }); // "2024-03-15" (already Friday -> returned as-is)
|
|
199
|
-
|
|
200
|
-
previousWeekday("2024-03-13", 5); // "2024-03-08" (Wednesday -> previous Friday)
|
|
201
|
-
previousWeekday("2024-03-15", 5); // "2024-03-08" (already Friday -> goes back a full week by default)
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
`dayOfWeek` uses Temporal's ISO numbering (1 = Monday … 7 = Sunday), the same as `getDayOfWeek`/`parseDayOfWeekFromDate`. These replace date-fns's sixteen `next*`/`previous*` functions with two parameterized calls (Decision 5, `context/roadmap/issues/J.md`):
|
|
205
|
-
|
|
206
|
-
| date-fns | GMT |
|
|
207
|
-
| ------------------ | ------------------------------ |
|
|
208
|
-
| `nextMonday(v)` | `nextWeekday(v, 1)` |
|
|
209
|
-
| `nextFriday(v)` | `nextWeekday(v, 5)` |
|
|
210
|
-
| `nextDay(v, n)` | `nextWeekday(v, n)` |
|
|
211
|
-
| `previousFriday(v)`| `previousWeekday(v, 5)` |
|
|
212
|
-
| `previousDay(v, n)`| `previousWeekday(v, n)` |
|
|
213
|
-
|
|
214
|
-
`date-fns`'s `lastDayOfMonth` is already covered by `endOfDate(value, "month")` — not a gap this pair fills.
|
|
215
|
-
|
|
216
|
-
## Common Mistakes
|
|
217
|
-
|
|
218
|
-
### HIGH Using string comparison for dates
|
|
219
|
-
|
|
220
|
-
Wrong:
|
|
221
|
-
|
|
222
|
-
```ts
|
|
223
|
-
const isAfter = "2024-03-20" > "2024-03-15"; // true but fragile
|
|
224
|
-
```
|
|
225
|
-
|
|
226
|
-
Correct:
|
|
227
|
-
|
|
228
|
-
```ts
|
|
229
|
-
import { isAfterDate } from "@northguild/gmt";
|
|
230
|
-
|
|
231
|
-
const isAfter = isAfterDate("2024-03-20", "2024-03-15"); // true
|
|
232
|
-
```
|
|
233
|
-
|
|
234
|
-
Source: AGENTS.md — Use Temporal for proper comparison
|
|
235
|
-
|
|
236
|
-
### MEDIUM Not handling invalid input
|
|
237
|
-
|
|
238
|
-
Wrong:
|
|
239
|
-
|
|
240
|
-
```ts
|
|
241
|
-
const result = isAfterDate("invalid", "2024-03-15");
|
|
242
|
-
// Assume result is always boolean
|
|
243
|
-
if (result) { // false, not throwing
|
|
244
|
-
process();
|
|
245
|
-
}
|
|
246
|
-
```
|
|
247
|
-
|
|
248
|
-
Correct:
|
|
249
|
-
|
|
250
|
-
```ts
|
|
251
|
-
import { isAfterDate, isValidDate } from "@northguild/gmt";
|
|
252
|
-
|
|
253
|
-
const dateA = "invalid";
|
|
254
|
-
const dateB = "2024-03-15";
|
|
255
|
-
if (!isValidDate(dateA) || !isValidDate(dateB)) {
|
|
256
|
-
throw new Error("Invalid date");
|
|
257
|
-
}
|
|
258
|
-
const result = isAfterDate(dateA, dateB);
|
|
259
|
-
```
|
|
260
|
-
|
|
261
|
-
Source: packages/gmt/src/plain/compare/isAfterDate.ts — Returns false on invalid
|
|
262
|
-
|
|
263
|
-
### MEDIUM Comparing different date formats
|
|
264
|
-
|
|
265
|
-
Wrong:
|
|
266
|
-
|
|
267
|
-
```ts
|
|
268
|
-
const result = isAfterDate("2024-3-5", "2024-03-15"); // may be incorrect
|
|
269
|
-
```
|
|
270
|
-
|
|
271
|
-
Correct:
|
|
272
|
-
|
|
273
|
-
```ts
|
|
274
|
-
// Ensure canonical format before comparison
|
|
275
|
-
import { isAfterDate } from "@northguild/gmt";
|
|
276
|
-
|
|
277
|
-
const result = isAfterDate("2024-03-05", "2024-03-15");
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
Source: Temporal.PlainDate.from() — canonicalizes input
|
|
281
|
-
|
|
282
|
-
### MEDIUM Assuming weekends are always Saturday/Sunday
|
|
283
|
-
|
|
284
|
-
Wrong:
|
|
285
|
-
|
|
286
|
-
```ts
|
|
287
|
-
import { getDayOfWeek } from "@northguild/gmt";
|
|
288
|
-
|
|
289
|
-
const day = getDayOfWeek(); // ISO day of week, always Monday-start
|
|
290
|
-
const isWeekendDay = day === 6 || day === 7; // wrong for he-IL/ar-SA (Fri/Sat)
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
Correct:
|
|
294
|
-
|
|
295
|
-
```ts
|
|
296
|
-
import { isWeekend } from "@northguild/gmt";
|
|
297
|
-
|
|
298
|
-
const isWeekendDay = isWeekend("2024-02-02", "he-IL"); // true — Friday is part of he-IL's weekend
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
Most locales use Saturday/Sunday, but `he-IL`/`ar-SA` use Friday/Saturday — `isWeekend`/`isZonedWeekend` resolve this per-locale via `Intl.Locale`'s `weekInfo` instead of hardcoding a day pair.
|
|
302
|
-
|
|
303
|
-
Source: packages/gmt/src/plain/compare/isWeekend.ts — locale-aware via Intl.Locale weekInfo
|
|
304
|
-
|
|
305
|
-
### MEDIUM Confusing isBusinessDay with isWeekend
|
|
306
|
-
|
|
307
|
-
Wrong:
|
|
308
|
-
|
|
309
|
-
```ts
|
|
310
|
-
const isWeekendDay = isBusinessDay("2024-02-02"); // false (it's a Friday)
|
|
311
|
-
// then assume isBusinessDay captures locale-specific weekend days
|
|
312
|
-
```
|
|
313
|
-
|
|
314
|
-
Correct:
|
|
315
|
-
|
|
316
|
-
```ts
|
|
317
|
-
import { isWeekend } from "@northguild/gmt";
|
|
318
|
-
|
|
319
|
-
// isBusinessDay is fixed ISO Mon–Fri (no locale lookup, no holidays)
|
|
320
|
-
isBusinessDay("2024-02-02"); // true (Friday)
|
|
321
|
-
|
|
322
|
-
// For locale-aware weekend detection (e.g. he-IL Fri/Sat), use isWeekend
|
|
323
|
-
isWeekend("2024-02-02", "he-IL"); // true (Friday is part of he-IL's weekend)
|
|
324
|
-
```
|
|
325
|
-
|
|
326
|
-
`isBusinessDay` uses a fixed Monday–Friday boundary and never consults `Intl.Locale`'s `weekInfo`; it does not account for holidays. Do not reach for it when you need locale-aware weekend detection — that's `isWeekend`/`isZonedWeekend`'s job.
|
|
327
|
-
|
|
328
|
-
Source: packages/gmt/src/plain/compare/isBusinessDay.ts — fixed ISO Mon–Fri, locale-agnostic
|
|
329
|
-
|
|
330
|
-
### MEDIUM Assuming "same month" ignores the year
|
|
331
|
-
|
|
332
|
-
Wrong:
|
|
333
|
-
|
|
334
|
-
```ts
|
|
335
|
-
import { areDatesEqualBy } from "@northguild/gmt";
|
|
336
|
-
|
|
337
|
-
// Assuming this checks "is it March, regardless of year"
|
|
338
|
-
const bothMarch = areDatesEqualBy("2023-03-15", "2024-03-15", "month"); // false, not true
|
|
339
|
-
```
|
|
340
|
-
|
|
341
|
-
Correct:
|
|
342
|
-
|
|
343
|
-
```ts
|
|
344
|
-
import { areDatesEqualBy } from "@northguild/gmt";
|
|
345
|
-
|
|
346
|
-
// "Same month" means the same month AND year — matches date-fns's isSameMonth
|
|
347
|
-
// and Luxon's dt.hasSame(other, "month")
|
|
348
|
-
areDatesEqualBy("2024-03-01", "2024-03-31", "month"); // true (same month, same year)
|
|
349
|
-
|
|
350
|
-
// To check "same month-of-year regardless of year", compare the month field directly
|
|
351
|
-
import { parseMonthFromDate } from "@northguild/gmt";
|
|
352
|
-
const sameMonthOfYear =
|
|
353
|
-
parseMonthFromDate("2023-03-15") === parseMonthFromDate("2024-03-15"); // true
|
|
354
|
-
```
|
|
355
|
-
|
|
356
|
-
`areDatesEqualBy(a, b, unit)` compares the start-of-`unit` boundary for each value, so any unit implicitly requires every coarser unit above it to match too — this is deliberate (Decision 5/6, `context/roadmap/issues/J.md`) and matches date-fns/Luxon precedent, not a GMT-specific quirk.
|
|
357
|
-
|
|
358
|
-
Source: packages/gmt/src/plain/compare/areDatesEqualBy.ts — start-of-unit comparison
|
|
359
|
-
|
|
360
|
-
### HIGH Assuming isRelativeDay/isThisUnit/isPast/isFuture are timeZone-independent
|
|
361
|
-
|
|
362
|
-
Wrong:
|
|
363
|
-
|
|
364
|
-
```ts
|
|
365
|
-
import { isRelativeDay } from "@northguild/gmt";
|
|
366
|
-
|
|
367
|
-
// Assuming "today" means the same thing everywhere
|
|
368
|
-
const isDueToday = isRelativeDay(dueDate, 0);
|
|
369
|
-
```
|
|
370
|
-
|
|
371
|
-
Correct:
|
|
372
|
-
|
|
373
|
-
```ts
|
|
374
|
-
import { isZonedRelativeDay } from "@northguild/gmt";
|
|
375
|
-
|
|
376
|
-
// "Today" is resolved in the value's own timeZone — deterministic
|
|
377
|
-
// regardless of the host machine's system timeZone
|
|
378
|
-
const isDueToday = isZonedRelativeDay(dueZonedDateTime, 0);
|
|
379
|
-
```
|
|
380
|
-
|
|
381
|
-
`isRelativeDay`/`isThisUnit`/`isPast`/`isFuture` depend on the **system clock and system timeZone** (they compare against `getToday()`). The same call returns different answers on hosts in different timeZones at the same instant — `isRelativeDay("2024-03-15", 0)` can be true in one timeZone and false in another 24 hours apart (e.g. `Pacific/Apia` vs. `Pacific/Niue`). Callers needing determinism — server-side rendering, tests, scheduled jobs — should use the zoned variants (`isZonedRelativeDay`, `isZonedThisUnit`, `isZonedPast`, `isZonedFuture`) with an explicit timeZone, or compare against an explicit reference with `areDatesEqualBy`/`isBeforeDate`/`isAfterDate`.
|
|
382
|
-
|
|
383
|
-
Source: packages/gmt/src/plain/compare/isRelativeDay.ts, packages/gmt/src/plain/get/getToday.ts — system clock/timeZone dependency
|
|
384
|
-
|
|
385
|
-
### MEDIUM Assuming nextWeekday/previousWeekday return the input when it's already on the target day
|
|
386
|
-
|
|
387
|
-
Wrong:
|
|
388
|
-
|
|
389
|
-
```ts
|
|
390
|
-
import { nextWeekday } from "@northguild/gmt";
|
|
391
|
-
|
|
392
|
-
// Assuming a Friday input returns itself when asking for "next Friday"
|
|
393
|
-
const result = nextWeekday("2024-03-15", 5); // "2024-03-22", not "2024-03-15"
|
|
394
|
-
```
|
|
395
|
-
|
|
396
|
-
Correct:
|
|
397
|
-
|
|
398
|
-
```ts
|
|
399
|
-
import { nextWeekday } from "@northguild/gmt";
|
|
400
|
-
|
|
401
|
-
// Pass { inclusive: true } to return the input as-is when it already falls on dayOfWeek
|
|
402
|
-
const result = nextWeekday("2024-03-15", 5, { inclusive: true }); // "2024-03-15"
|
|
403
|
-
```
|
|
404
|
-
|
|
405
|
-
`options.inclusive` defaults to `false`, matching date-fns: a `value` already on `dayOfWeek` advances a full week rather than returning itself. Same default applies to `previousWeekday`.
|
|
406
|
-
|
|
407
|
-
Source: packages/gmt/src/plain/calculate/nextWeekday.ts, packages/gmt/src/plain/calculate/previousWeekday.ts — inclusive defaults to false
|
|
408
|
-
|
|
409
|
-
## References
|
|
410
|
-
|
|
411
|
-
- [Full compare API](references/compare-api.md)
|
|
412
|
-
- [Temporal.PlainDate comparison](https://tc39.es/proposal-temporal/docs/plaindate.html#comparison)
|