Skip to content

Commit 9ac8926

Browse files
authored
test(refresh-rate-limiter-timezone-boundaries): verify Timezone Normalization & Calendar Data Boundary Alignment (Variation 8) (JhaSourav07#3027)
## Description Fixes JhaSourav07#2950 ## Pillar - [ ] 🎨 Pillar 1 — New Theme Design - [ ] 📐 Pillar 2 — Geometric SVG Improvement - [x] 🕐 Pillar 3 — Timezone Logic Optimization - [x] 🛠️ Other (Bug fix, refactoring, docs) ## Visual Preview ## Checklist before requesting a review: - [x] I have read the `CONTRIBUTING.md` file. - [x] I have tested these changes locally (`localhost:3000/api/streak?user=YOUR_USERNAME`). - [x] I have run `npm run format` and `npm run lint` locally and resolved all errors (CI will fail otherwise). - [x] My commits follow the Conventional Commits format (e.g., `feat(themes): ...`, `fix(calculate): ...`). - [x] I have updated `README.md` if I added a new theme or URL parameter. - [x] I have started the repo. - [x] I have made sure that i have only one commit to merge in this PR. - [x] The SVG output matches the CommitPulse "premium quality" aesthetic standard (no raw elements, smooth animations, correct fonts). - [x] (Recommended) I joined the CommitPulse Discord community for contributor discussions, mentorship, and faster PR support. closes JhaSourav07#2950
2 parents 465f7cc + 51d2b8c commit 9ac8926

1 file changed

Lines changed: 85 additions & 0 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2+
import { getSecondsUntilMidnightInTimezone } from '../../utils/time';
3+
4+
function partsForTZ(date: Date, tz: string) {
5+
const parts = new Intl.DateTimeFormat('en-US', {
6+
timeZone: tz,
7+
year: 'numeric',
8+
month: 'numeric',
9+
day: 'numeric',
10+
}).formatToParts(date);
11+
const get = (t: string) => parseInt(parts.find((p) => p.type === t)?.value ?? '0', 10);
12+
return { year: get('year'), month: get('month'), day: get('day') };
13+
}
14+
15+
describe('Timezone normalization & calendar boundary alignment', () => {
16+
beforeEach(() => vi.useFakeTimers());
17+
afterEach(() => vi.useRealTimers());
18+
19+
it('maps UTC timestamp to Asia/Kolkata local date across a leap-year boundary', () => {
20+
// UTC 2024-02-28T18:45:00Z -> Asia/Kolkata 2024-02-29T00:15:00+05:30 (leap day)
21+
vi.setSystemTime(new Date('2024-02-28T18:45:00.000Z'));
22+
23+
const now = new Date();
24+
const p = partsForTZ(now, 'Asia/Kolkata');
25+
26+
expect(p.year).toBe(2024);
27+
expect(p.month).toBe(2);
28+
expect(p.day).toBe(29);
29+
});
30+
31+
it('verifies consecutive UTC days map to consecutive local dates (no gaps on leap year)', () => {
32+
const utcDates = [
33+
new Date('2024-02-28T00:00:00.000Z'),
34+
new Date('2024-02-29T00:00:00.000Z'),
35+
new Date('2024-03-01T00:00:00.000Z'),
36+
];
37+
38+
const localDays = utcDates.map((d) => {
39+
const p = partsForTZ(d, 'Asia/Kolkata');
40+
return p.day;
41+
});
42+
43+
expect(localDays).toEqual([28, 29, 1]);
44+
});
45+
46+
it('produces expected locale date strings for en-US and en-GB', () => {
47+
const d = new Date('2024-06-15T00:00:00.000Z');
48+
49+
const us = d.toLocaleDateString('en-US', { timeZone: 'UTC' });
50+
const gb = d.toLocaleDateString('en-GB', { timeZone: 'UTC' });
51+
52+
// en-US: M/D/YYYY | en-GB: D/M/YYYY
53+
expect(us).toMatch(/6\/?15\/?2024/);
54+
expect(gb).toMatch(/15\/?06\/?2024/);
55+
expect(us).not.toBe(gb);
56+
});
57+
58+
it('handles daylight saving transitions in America/New_York (spring-forward) without throwing and shows differing TTLs', () => {
59+
// Before DST jump: 2024-03-10T06:30:00Z => 01:30 EST (UTC-5)
60+
vi.setSystemTime(new Date('2024-03-10T06:30:00.000Z'));
61+
const before = getSecondsUntilMidnightInTimezone('America/New_York');
62+
63+
// After the jump one hour later in UTC: 2024-03-10T07:30:00Z => 03:30 EDT (UTC-4)
64+
vi.setSystemTime(new Date('2024-03-10T07:30:00.000Z'));
65+
const after = getSecondsUntilMidnightInTimezone('America/New_York');
66+
67+
expect(Number.isInteger(before)).toBe(true);
68+
expect(Number.isInteger(after)).toBe(true);
69+
// TTLs should be non-negative and, due to the DST shift, differ from one another
70+
expect(before).toBeGreaterThanOrEqual(0);
71+
expect(after).toBeGreaterThanOrEqual(0);
72+
expect(before).not.toBe(after);
73+
});
74+
75+
it('ensures Asia/Tokyo offsets move commits across midnight to next visual date', () => {
76+
// UTC 2024-06-14T15:30:00Z -> Asia/Tokyo 2024-06-15T00:30:00+09:00
77+
vi.setSystemTime(new Date('2024-06-14T15:30:00.000Z'));
78+
79+
const p = partsForTZ(new Date(), 'Asia/Tokyo');
80+
81+
expect(p.year).toBe(2024);
82+
expect(p.month).toBe(6);
83+
expect(p.day).toBe(15);
84+
});
85+
});

0 commit comments

Comments
 (0)