Skip to content

Commit 750d50d

Browse files
morethanwordsclaude
andcommitted
Dates: month names run from January to December in every timezone
West of UTC the list of month names began with December and had no February: it was built from a UTC midnight on January 1st, which the formatter reads in local time as December 31st, and stepping that 31st by a month skipped February. The birthday popup saves the month a name stands at, so there "January" saved February, and the bubbles that name a month by its number named the wrong one. Each name is now taken from the middle of its month in local time, as the week days next to it already are. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 04bff39 commit 750d50d

3 files changed

Lines changed: 39 additions & 25 deletions

File tree

‎src/helpers/date.ts‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ export function getWeekDays() {
4444

4545
export function getMonths() {
4646
const dateTimeFormat = I18n.getDateTimeFormat({month: 'long'});
47-
const date = new Date(Date.UTC(2017, 0, 1));
47+
// The middle of each month in local time, as the formatter reads it: a UTC midnight on
48+
// January 1st is still December west of Greenwich, and stepping that 31st skipped February.
4849
const out: string[] = [];
4950
for(let i = 0; i < 12; ++i) {
50-
out.push(capitalizeFirstLetter(dateTimeFormat.format(date)));
51-
date.setMonth(date.getMonth() + 1);
51+
out.push(capitalizeFirstLetter(dateTimeFormat.format(new Date(2017, i, 15))));
5252
}
5353
return out;
5454
}

‎src/tests/getWeekDays.test.ts‎

Lines changed: 0 additions & 22 deletions
This file was deleted.
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import {getMonths, getWeekDays} from '@helpers/date';
2+
3+
// A fresh formatter per call, so each one picks up the timezone the test sets.
4+
vi.mock('@lib/langPack', () => ({
5+
default: {
6+
getDateTimeFormat: (options: Intl.DateTimeFormatOptions) => new Intl.DateTimeFormat('en', options)
7+
}
8+
}));
9+
10+
const ZONES = ['America/Los_Angeles', 'UTC', 'Asia/Tokyo'];
11+
12+
const tz = process.env.TZ;
13+
afterEach(() => {
14+
process.env.TZ = tz;
15+
});
16+
17+
describe('getWeekDays', () => {
18+
// The schedule it labels (OpeningHours.getDaysHours) starts on Monday whatever
19+
// the timezone, so the labels have to as well.
20+
test.each(ZONES)('starts on Monday in %s', (zone) => {
21+
process.env.TZ = zone;
22+
expect(getWeekDays()).toEqual(['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']);
23+
});
24+
});
25+
26+
describe('getMonths', () => {
27+
// The birthday popup saves the month a name stands at here (index + 1), and the
28+
// chat names a month by its number from the same list.
29+
test.each(ZONES)('runs from January to December in %s', (zone) => {
30+
process.env.TZ = zone;
31+
expect(getMonths()).toEqual([
32+
'January', 'February', 'March', 'April', 'May', 'June',
33+
'July', 'August', 'September', 'October', 'November', 'December'
34+
]);
35+
});
36+
});

0 commit comments

Comments
 (0)