diff --git a/frontend/src/commonMain/resources/std/temporal/temporal.temper.md b/frontend/src/commonMain/resources/std/temporal/temporal.temper.md index 6755d9c32..995461d4a 100644 --- a/frontend/src/commonMain/resources/std/temporal/temporal.temper.md +++ b/frontend/src/commonMain/resources/std/temporal/temporal.temper.md @@ -219,14 +219,19 @@ Here's just enough of a Date type to get us started. */ @connected public get dayOfWeek(): Int { - // Gauss's method. + // Gauss's method: January first of year Y is weekday + // (1 + 5((Y-1) mod 4) + 4((Y-1) mod 100) + 6((Y-1) mod 400)) mod 7, + // with Sunday 0. It is Y - 1 that splits into century and year: + // splitting Y instead is wrong for every year ending in 00 that + // is not a multiple of 400, such as 1900 and 2100. + // `%` keeps the dividend's sign, so each remainder adds its + // divisor and takes it again, to stay in range for years before 1. let y = year; - let c = if (y >= 0) { y / 100 } else { -(-y / 100) }; - let yy = y - (c * 100); - // See note below about avoiding negative modulus to see why - // some of the offsets differ from Wikipedia's rendering of - // Gauss's formula. - let janFirst = (8 + 5*((yy + 3) % 4) + 3*(yy - 1) + 5*(c % 4)) % 7; + let before = y - 1; + let mod4 = ((before % 4) + 4) % 4; + let mod100 = ((before % 100) + 100) % 100; + let mod400 = ((before % 400) + 400) % 400; + let janFirst = (1 + 5 * mod4 + 4 * mod100 + 6 * mod400) % 7; let table = if (isLeapYear(y)) { dayOfWeekLookupTableLeapy } else { diff --git a/functional-test-suite/src/commonMain/resources/types/date/date.temper.md b/functional-test-suite/src/commonMain/resources/types/date/date.temper.md index 3bf436e9a..0cde50130 100644 --- a/functional-test-suite/src/commonMain/resources/types/date/date.temper.md +++ b/functional-test-suite/src/commonMain/resources/types/date/date.temper.md @@ -78,6 +78,25 @@ ISO 8601 yonks: 0012-11-10 yonksAgo.year = 12 ``` +The weekday of a year ending in 00 needs the right century. A +January first or March first of 1900 or 2100 lands on a different day +than in 2000, since 2000 is a leap year and the others are not. + + for (let y of [1700, 1800, 1900, 2000, 2100, 2400]) { + console.log( + "${y}: Jan 1 weekday ${new Date(y, 1, 1).dayOfWeek}, Mar 1 weekday ${new Date(y, 3, 1).dayOfWeek}" + ); + } + +```log +1700: Jan 1 weekday 5, Mar 1 weekday 1 +1800: Jan 1 weekday 3, Mar 1 weekday 6 +1900: Jan 1 weekday 1, Mar 1 weekday 4 +2000: Jan 1 weekday 6, Mar 1 weekday 3 +2100: Jan 1 weekday 5, Mar 1 weekday 1 +2400: Jan 1 weekday 6, Mar 1 weekday 3 +``` + TODO: test negative year support once we've got a story for Python whose datetime.MIN_YEAR == 1.