Skip to content

Commit 51c1364

Browse files
committed
Route Day.js operations through injected factory
1 parent a5d12be commit 51c1364

3 files changed

Lines changed: 79 additions & 6 deletions

File tree

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@salt-ds/date-adapters": patch
3+
---
4+
5+
Fixed the Day.js adapter to consistently use an injected Day.js factory for timezone resolution, UTC/timezone date creation, `today`, and `now`.

packages/date-adapters/src/__tests__/dayjs.spec.ts

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import dayjs from "dayjs";
2+
import "dayjs/locale/fr";
23
import customParseFormat from "dayjs/plugin/customParseFormat";
34
import timezone from "dayjs/plugin/timezone";
45
import utc from "dayjs/plugin/utc";
@@ -11,9 +12,76 @@ dayjs.extend(utc);
1112
dayjs.extend(timezone);
1213
dayjs.extend(customParseFormat);
1314

15+
const createInjectedDayjs = () => {
16+
const fixedNow = "2030-06-15T12:34:56.000Z";
17+
const systemTimezone = "Asia/Tokyo";
18+
const injectedTimezone = ((
19+
value?: Parameters<typeof dayjs.tz>[0],
20+
timezone?: string,
21+
) => dayjs.tz(value ?? fixedNow, timezone)) as typeof dayjs.tz;
22+
injectedTimezone.guess = () => systemTimezone;
23+
injectedTimezone.setDefault = dayjs.tz.setDefault;
24+
const injectedUtc = ((...args: Parameters<typeof dayjs.utc>) =>
25+
args.length === 0 ? dayjs.utc(fixedNow) : dayjs.utc(...args)) as typeof dayjs.utc;
26+
const factory = Object.assign(
27+
(...args: Parameters<typeof dayjs>) =>
28+
args.length === 0 ? dayjs(fixedNow) : dayjs(...args),
29+
{ tz: injectedTimezone, utc: injectedUtc },
30+
);
31+
32+
return { factory, fixedNow, systemTimezone };
33+
};
34+
1435
describe("GIVEN a AdapterDayjs", () => {
1536
const adapter = new AdapterDayjs({ locale: "en" });
1637

38+
describe("GIVEN an injected Day.js factory", () => {
39+
const { factory, fixedNow, systemTimezone } = createInjectedDayjs();
40+
const injectedAdapter = new AdapterDayjs({ locale: "fr" }, factory);
41+
42+
it.each(["default", "system"] as const)(
43+
"SHOULD use its timezone configuration for %s dates",
44+
(timezone) => {
45+
const date = injectedAdapter.date("2025-01-05T00:00:00", timezone);
46+
47+
expect(injectedAdapter.getTimezone(date)).toBe(systemTimezone);
48+
expect(date.format("Z")).toBe("+09:00");
49+
},
50+
);
51+
52+
it("SHOULD use its UTC factory", () => {
53+
const date = injectedAdapter.date("2025-01-05T00:00:00", "UTC");
54+
55+
expect(date.utcOffset()).toBe(0);
56+
});
57+
58+
it("SHOULD use its timezone factory for an explicit IANA timezone", () => {
59+
const date = injectedAdapter.date(
60+
"2025-01-05T00:00:00",
61+
"America/New_York",
62+
);
63+
64+
expect(injectedAdapter.getTimezone(date)).toBe("America/New_York");
65+
expect(date.format("Z")).toBe("-05:00");
66+
});
67+
68+
it("SHOULD apply the configured locale", () => {
69+
const date = injectedAdapter.date("2025-01-05T00:00:00", "UTC");
70+
71+
expect(injectedAdapter.format(date, "MMMM")).toBe("janvier");
72+
});
73+
74+
it("SHOULD use its clock for today", () => {
75+
expect(injectedAdapter.today("UTC").format("YYYY-MM-DD HH:mm:ss")).toBe(
76+
"2030-06-15 00:00:00",
77+
);
78+
});
79+
80+
it("SHOULD use its clock for now", () => {
81+
expect(injectedAdapter.now("UTC").toISOString()).toBe(fixedNow);
82+
});
83+
});
84+
1785
it("SHOULD create a Dayjs date in the system timezone", () => {
1886
const date = adapter.date("2023-11-01", "system");
1987
expect(date.isValid()).toBe(true);

packages/date-adapters/src/dayjs-adapter/index.ts

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,8 @@ import {
1616

1717
type Constructor = {
1818
(...args: Parameters<typeof defaultDayjs>): Dayjs;
19-
tz?: (value: Parameters<typeof defaultDayjs>[0], timezone: string) => Dayjs;
20-
utc?: (value?: Parameters<typeof defaultDayjs>[0]) => Dayjs;
19+
tz?: typeof defaultDayjs.tz;
20+
utc?: typeof defaultDayjs.utc;
2121
};
2222

2323
declare module "@salt-ds/date-adapters" {
@@ -88,7 +88,7 @@ export class AdapterDayjs implements SaltDateAdapter<Dayjs, string> {
8888
return undefined;
8989
}
9090
if (timezone === "system") {
91-
return defaultDayjs.tz.guess();
91+
return this.dayjs.tz?.guess();
9292
}
9393
return timezone;
9494
};
@@ -102,11 +102,11 @@ export class AdapterDayjs implements SaltDateAdapter<Dayjs, string> {
102102
if (!this.dayjs.tz) {
103103
throw new Error("Salt Day.js adapter: missing timezone plugin");
104104
}
105-
const timezone = defaultDayjs.tz.guess();
105+
const timezone = this.dayjs.tz.guess();
106106
if (timezone !== "UTC") {
107-
return defaultDayjs.tz(value, timezone);
107+
return this.dayjs.tz(value, timezone);
108108
}
109-
return defaultDayjs(value);
109+
return this.dayjs(value);
110110
};
111111

112112
/**

0 commit comments

Comments
 (0)