Skip to content

Commit f916df9

Browse files
committed
Fix a bug when a year is a 2-digit number in toDateFromClockTime
1 parent 16e50e8 commit f916df9

File tree

3 files changed

+85
-7
lines changed

3 files changed

+85
-7
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import type { GenericDateConstructor } from "../types.js";
2+
3+
export function createDateFromClockTime<DateType extends Date>(
4+
DateConstructor: GenericDateConstructor<DateType>,
5+
year: number,
6+
month: number,
7+
day = 1,
8+
hour = 0,
9+
minute = 0,
10+
second = 0,
11+
millisecond = 0,
12+
): DateType {
13+
if (year >= 0 && year <= 99) {
14+
// assumption: there is no time zone transition in ancient times
15+
// additionally (just in case) 2024-01-05T00:00:00 should exist in all time zones
16+
const date = new DateConstructor(2024, 0, 5);
17+
date.setFullYear(year, month - 1, day);
18+
date.setHours(hour, minute, second, millisecond);
19+
return date;
20+
}
21+
return new DateConstructor(
22+
year,
23+
month - 1,
24+
day,
25+
hour,
26+
minute,
27+
second,
28+
millisecond,
29+
);
30+
}

src/datetime/toDateFromClockTime.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,3 +141,15 @@ test("date constructor type", () => {
141141
UTCDate,
142142
);
143143
});
144+
145+
test("2-digit year", () => {
146+
expect(
147+
toDateFromClockTime(Temporal.PlainDateTime.from("0050-01-01")),
148+
).toEqual(new UTCDate("0050-01-01T00:00:00Z"));
149+
expect(toDateFromClockTime(Temporal.PlainDate.from("0050-01-01"))).toEqual(
150+
new UTCDate("0050-01-01T00:00:00Z"),
151+
);
152+
expect(
153+
toDateFromClockTime(Temporal.PlainYearMonth.from("0050-01-01")),
154+
).toEqual(new UTCDate("0050-01-01T00:00:00Z"));
155+
});

src/datetime/toDateFromClockTime.ts

Lines changed: 43 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
isZonedDateTime,
99
} from "../type-utils.js";
1010
import type { GenericDateConstructor, Temporal } from "../types.js";
11+
import { createDateFromClockTime } from "./_createDateFromClockTime.js";
1112

1213
function parseIsoString(date: string) {
1314
const res = /^(\d{4,}|[+-]\d{6})-(\d{2})-(\d{2})/.exec(date);
@@ -25,6 +26,40 @@ function parseIsoString(date: string) {
2526
};
2627
}
2728

29+
// function to bypass an enigmatic TypeScript error "could be instantiated with a different subtype of constraint"
30+
function createDate<DateType extends Date>(
31+
DateConstructor: GenericDateConstructor<DateType> | undefined,
32+
year: number,
33+
month: number,
34+
day = 1,
35+
hour = 0,
36+
minute = 0,
37+
second = 0,
38+
millisecond = 0,
39+
) {
40+
return DateConstructor ?
41+
createDateFromClockTime(
42+
DateConstructor,
43+
year,
44+
month,
45+
day,
46+
hour,
47+
minute,
48+
second,
49+
millisecond,
50+
)
51+
: createDateFromClockTime(
52+
UTCDate,
53+
year,
54+
month,
55+
day,
56+
hour,
57+
minute,
58+
second,
59+
millisecond,
60+
);
61+
}
62+
2863
/**
2964
* Returns `Date` which represents clock (local) time of given temporal object,
3065
* dropping timezone and calendar information.
@@ -79,22 +114,22 @@ export function toDateFromClockTime<DateType extends Date>(
79114
| Temporal.PlainMonthDay,
80115
DateConstructor?: GenericDateConstructor<DateType>,
81116
) {
82-
const DateConstructorFunction = DateConstructor ?? UTCDate;
83117
if (isPlainYearMonth(dateTime)) {
84118
const pd = dateTime.toPlainDate({ day: 1 }).withCalendar("iso8601");
85-
return new DateConstructorFunction(pd.year, pd.month - 1, pd.day);
119+
return createDate(DateConstructor, pd.year, pd.month, pd.day);
86120
}
87121
if (isPlainMonthDay(dateTime)) {
88122
if (dateTime.calendarId === "iso8601") {
89123
const pd = dateTime.toPlainDate({ year: 1972 });
90-
return new DateConstructorFunction(pd.year, pd.month - 1, pd.day);
124+
return createDate(DateConstructor, pd.year, pd.month, pd.day);
91125
}
92126
const { year, month, day } = parseIsoString(dateTime.toString());
93-
return new DateConstructorFunction(year, month - 1, day);
127+
return createDate(DateConstructor, year, month, day);
94128
}
95129
if (isPlainTime(dateTime)) {
96130
// Set default date to 2000-01-01
97-
return new DateConstructorFunction(
131+
return createDate(
132+
DateConstructor,
98133
2000,
99134
0,
100135
1,
@@ -109,9 +144,10 @@ export function toDateFromClockTime<DateType extends Date>(
109144
dateTime.toPlainDateTime().withCalendar("iso8601")
110145
: isPlainDate(dateTime) ? dateTime.toPlainDateTime().withCalendar("iso8601")
111146
: dateTime.withCalendar("iso8601");
112-
return new DateConstructorFunction(
147+
return createDate(
148+
DateConstructor,
113149
plainDateTime.year,
114-
plainDateTime.month - 1,
150+
plainDateTime.month,
115151
plainDateTime.day,
116152
plainDateTime.hour,
117153
plainDateTime.minute,

0 commit comments

Comments
 (0)