Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 12 additions & 7 deletions frontend/src/commonMain/resources/std/temporal/temporal.temper.md
Original file line number Diff line number Diff line change
Expand Up @@ -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) };

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ugh. I probably meant to do something with ~ instead of - here.

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 {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, here's an attempt to use date to double check these.

$ for y in {17,18,19,20,21,24}00; do echo "$y Jan 1 weekday $(date -j -f "%Y-%m-%d" $y-01-01 +%u), Mar 1 weekday $(date -j -f "%Y-%m-%d" $y-03-01 +%u)"; done
date: nonexistent time
date: nonexistent time
1700 Jan 1 weekday , Mar 1 weekday
date: nonexistent time
date: nonexistent time
1800 Jan 1 weekday , Mar 1 weekday
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

I'm guessing the nonexistent time thing is due to a failure to just use a proleptic Gregorian calendar.

My man cal says the below, so I'll not muck with that.

BUGS
The assignment of Julian鈥揋regorian switching dates to country codes is historically naive for many countries.

Java's java.time.LocalDate says:

The ISO-8601 calendar system is the modern civil calendar system used today in most of the world. It is equivalent to the proleptic Gregorian calendar system

And its DayOfWeek.getValue returns the ISO's 1-indexed weekday number starting at 1 = Monday.

Here's the output of jshell using that.

$ jshell
|  Welcome to JShell -- Version 21.0.4
|  For an introduction type: /help intro

jshell> import java.time.LocalDate;

jshell> for (int year : new int[] { 1700, 1800, 1900, 2000, 2100, 2400}) {
   ...>     LocalDate jan1 = LocalDate.of(year, 1, 1);
   ...>     LocalDate mar1 = LocalDate.of(year, 3, 1);
   ...>     System.err.println(year + ": Jan 1 weekday " + (jan1.getDayOfWeek().getValue()) + ", Mar 1 weekday " + (mar1.getDayOfWeek().getValue()));
   ...> }
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

jshell>

```

TODO: test negative year support once we've got a
story for Python whose datetime.MIN_YEAR == 1.

Expand Down
Loading