Add getWeekInfo(locale) -> { firstDay, weekend } to $libs/days (Intl
convention, 1 = Monday ... 7 = Sunday): firstDay mirrors the internal
getWeekStart (Intl weekInfo + region-table fallback — one source of truth,
now exported from the vendored port), weekend comes from Intl.Locale
weekInfo (getWeekInfo() method or the Safari weekInfo accessor) with the
DOCUMENTED Saturday/Sunday fallback. Cached per locale.
Calendar + RangeCalendar derive their weekend flag from it: the shared
helpers.isWeekend(date) hardcoded Sat/Sun against a fixed 'en-US' — wrong
for e.g. ar-SA (Fri/Sat) — and now takes the provider's effectiveLocale.
Verified live: data-weekend moves to Fri+Sat under ar-SA, stays Sat+Sun
for en-US / es-ES; firstDay verified (es-ES Monday-first, en-US
Sunday-first grids; explicit weekStartsOn still overrides).
Directed firstDay verification also caught getSimpleWeekNumber mixing
frames: an ABSOLUTE weekStartsOn (0 = Sunday) was passed to
getLastFirstDayOfWeek with the display locale, which re-interprets the
index relative to that locale's own week start — es-ES 'simple' week
numbers anchored the year on a Tuesday and ran one week behind. Anchor in
the fixed en-US frame (same convention as buildMonth's explicit branch);
the dead locale param is removed from both call sites.
Tests: getWeekInfo (es-ES / en-US / ar-SA / cache identity) + new calendar
helpers suite (locale weekend, grid week-start per locale, week-number
regression). Suites 15/15, baseline 59.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
menubar-v4-safe
parent
83e13be649
commit
3b02fd11a5
@ -0,0 +1,53 @@
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { CalendarDate } from '$libs/days';
|
||||
|
||||
import { createMonths, getSimpleWeekNumber, isWeekend } from './helpers';
|
||||
|
||||
// 2026-07-10 = Friday, 2026-07-11 = Saturday, 2026-07-12 = Sunday.
|
||||
const FRI = new CalendarDate(2026, 7, 10);
|
||||
const SAT = new CalendarDate(2026, 7, 11);
|
||||
const SUN = new CalendarDate(2026, 7, 12);
|
||||
|
||||
describe('isWeekend (locale-aware, C6)', () => {
|
||||
it('es-ES: Sat/Sun weekend', () => {
|
||||
expect(isWeekend(FRI, 'es-ES')).toBe(false);
|
||||
expect(isWeekend(SAT, 'es-ES')).toBe(true);
|
||||
expect(isWeekend(SUN, 'es-ES')).toBe(true);
|
||||
});
|
||||
|
||||
it('ar-SA: Fri/Sat weekend (CLDR weekInfo), Sunday is a weekday', () => {
|
||||
expect(isWeekend(FRI, 'ar-SA')).toBe(true);
|
||||
expect(isWeekend(SAT, 'ar-SA')).toBe(true);
|
||||
expect(isWeekend(SUN, 'ar-SA')).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('createMonths firstDay (locale week start)', () => {
|
||||
const opts = { numberOfMonths: 1, weekStartsOn: undefined, fixedWeeks: false };
|
||||
|
||||
it('es-ES grids start on Monday', () => {
|
||||
// July 2026 starts on a Wednesday → the leading cell is Mon 2026-06-29.
|
||||
const [july] = createMonths(new CalendarDate(2026, 7, 15), { ...opts, locale: 'es-ES' });
|
||||
expect(july.weeks[0][0].toString()).toBe('2026-06-29');
|
||||
});
|
||||
|
||||
it('en-US grids start on Sunday', () => {
|
||||
const [july] = createMonths(new CalendarDate(2026, 7, 15), { ...opts, locale: 'en-US' });
|
||||
expect(july.weeks[0][0].toString()).toBe('2026-06-28');
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSimpleWeekNumber (absolute weekStartsOn frame)', () => {
|
||||
// 2026-01-01 = Thursday. Sunday-start anchor: Sun 2025-12-28; Monday-start
|
||||
// anchor: Mon 2025-12-29. The row starting Mon 2026-01-05 is week 2 in both
|
||||
// framings — the old locale-mixed anchor (es-ES) shifted it to week 1.
|
||||
it('week containing January 1 is week 1', () => {
|
||||
expect(getSimpleWeekNumber(new CalendarDate(2026, 1, 1), 0)).toBe(1);
|
||||
expect(getSimpleWeekNumber(new CalendarDate(2026, 1, 1), 1)).toBe(1);
|
||||
});
|
||||
|
||||
it('the next row is week 2 regardless of the display locale (regression)', () => {
|
||||
expect(getSimpleWeekNumber(new CalendarDate(2026, 1, 4), 0)).toBe(2);
|
||||
expect(getSimpleWeekNumber(new CalendarDate(2026, 1, 5), 1)).toBe(2);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in new issue