doomsday: continue writing

This commit is contained in:
Moritz Hölting 2026-03-20 15:05:57 +01:00
parent 72cbae88e0
commit 104e8e9891
8 changed files with 1268 additions and 193 deletions

View File

@ -7,6 +7,7 @@ import rehypeKatex from "rehype-katex";
import matomo from "./src/integrations/matomo"; import matomo from "./src/integrations/matomo";
import tailwindcss from "@tailwindcss/vite"; import tailwindcss from "@tailwindcss/vite";
import icon from "astro-icon"; import icon from "astro-icon";
import mermaid from "astro-mermaid";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
@ -14,8 +15,16 @@ export default defineConfig({
trailingSlash: "always", trailingSlash: "always",
integrations: [ integrations: [
mdx(),
sitemap(), sitemap(),
mermaid({
autoTheme: true,
mermaidConfig: {
themeVariables: {
fontFamily: '"FiraCode", monospace',
},
},
}),
mdx(),
icon(), icon(),
solidJs(), solidJs(),
matomo({ matomo({
@ -39,5 +48,8 @@ export default defineConfig({
server: { server: {
watch: {}, watch: {},
}, },
optimizeDeps: {
include: ["mermaid"],
},
}, },
}); });

View File

@ -28,11 +28,13 @@
"@tailwindcss/vite": "^4.2.1", "@tailwindcss/vite": "^4.2.1",
"astro": "^6.0.5", "astro": "^6.0.5",
"astro-icon": "^1.1.5", "astro-icon": "^1.1.5",
"astro-mermaid": "^2.0.1",
"astro-og-canvas": "^0.10.1", "astro-og-canvas": "^0.10.1",
"canvaskit-wasm": "^0.40.0", "canvaskit-wasm": "^0.40.0",
"clsx": "^2.1.1", "clsx": "^2.1.1",
"fuse.js": "^7.1.0", "fuse.js": "^7.1.0",
"iconify-icon": "^3.0.2", "iconify-icon": "^3.0.2",
"mermaid": "^11.13.0",
"rehype-katex": "^7.0.1", "rehype-katex": "^7.0.1",
"remark-math": "^6.0.0", "remark-math": "^6.0.0",
"sharp": "^0.34.5", "sharp": "^0.34.5",

File diff suppressed because it is too large Load Diff

View File

@ -1,67 +1,77 @@
function changeTheme() { function changeTheme() {
const element = document.documentElement const element = document.documentElement;
const theme = element.classList.contains("dark") ? "light" : "dark" const theme = element.classList.contains("dark") ? "light" : "dark";
const css = document.createElement("style") const css = document.createElement("style");
css.appendChild( css.appendChild(
document.createTextNode( document.createTextNode(
`* { `* {
-webkit-transition: none !important; -webkit-transition: none !important;
-moz-transition: none !important; -moz-transition: none !important;
-o-transition: none !important; -o-transition: none !important;
-ms-transition: none !important; -ms-transition: none !important;
transition: none !important; transition: none !important;
}`, }`,
), ),
) );
document.head.appendChild(css) document.head.appendChild(css);
if (theme === "dark") { if (theme === "dark") {
element.classList.add("dark") element.classList.add("dark");
} else { element.dataset.theme = "dark";
element.classList.remove("dark") } else {
} element.classList.remove("dark");
element.dataset.theme = "light";
}
window.getComputedStyle(css).opacity window.getComputedStyle(css).opacity;
document.head.removeChild(css) document.head.removeChild(css);
localStorage.theme = theme localStorage.theme = theme;
} }
function preloadTheme() { function preloadTheme() {
const theme = (() => { const theme = (() => {
const userTheme = localStorage.theme const userTheme = localStorage.theme;
if (userTheme === "light" || userTheme === "dark") { if (userTheme === "light" || userTheme === "dark") {
return userTheme return userTheme;
} else {
return window.matchMedia("(prefers-color-scheme: dark)").matches
? "dark"
: "light";
}
})();
const element = document.documentElement;
if (theme === "dark") {
element.classList.add("dark");
element.dataset.theme = "dark";
} else { } else {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light" element.classList.remove("dark");
element.dataset.theme = "light";
} }
})()
const element = document.documentElement localStorage.theme = theme;
if (theme === "dark") {
element.classList.add("dark")
} else {
element.classList.remove("dark")
}
localStorage.theme = theme
} }
window.onload = () => { window.onload = () => {
function initializeThemeButtons() { function initializeThemeButtons() {
const headerThemeButton = document.getElementById("header-theme-button") const headerThemeButton = document.getElementById(
const drawerThemeButton = document.getElementById("drawer-theme-button") "header-theme-button",
headerThemeButton?.addEventListener("click", changeTheme) );
drawerThemeButton?.addEventListener("click", changeTheme) const drawerThemeButton = document.getElementById(
} "drawer-theme-button",
);
document.addEventListener("astro:after-swap", initializeThemeButtons) headerThemeButton?.addEventListener("click", changeTheme);
initializeThemeButtons() drawerThemeButton?.addEventListener("click", changeTheme);
} }
document.addEventListener("astro:after-swap", preloadTheme) document.addEventListener("astro:after-swap", initializeThemeButtons);
initializeThemeButtons();
};
preloadTheme() document.addEventListener("astro:after-swap", preloadTheme);
preloadTheme();

View File

@ -1,136 +0,0 @@
---
import { cn } from "@/lib/utils";
export interface Props {
display:
| "weekday"
| "weekday-number"
| "year"
| "january-day"
| "february-day";
prefix?: string;
suffix?: string;
offset?: number;
valueClass?: string;
}
const {
display,
prefix,
suffix,
offset,
valueClass: customClass,
} = Astro.props;
---
<span class={cn(`doomsday-display doomsday-${display}`)}
>{prefix}<span
class={cn("doomsday-value", customClass)}
data-offset={offset}>...</span
>{suffix}</span
>
<script>
function isLeapYear(year: number) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}
function handleOffset<T>(
element: HTMLElement,
fn: (offset: number) => T,
): T {
const offset = parseInt(element.dataset.offset || "0");
return fn(offset);
}
const weekdays = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const currentYearInput = document.getElementById(
"doomsday-year",
) as HTMLInputElement | null;
function update() {
const selectedYear = currentYearInput
? parseInt(currentYearInput.value)
: new Date().getFullYear();
console.log("Selected Year:", selectedYear);
const isSelectedYearLeap = isLeapYear(selectedYear);
const febDoomsdayDay = 28 + (isSelectedYearLeap ? 1 : 0);
// Display the selected year
const yearElements = document.querySelectorAll(
".doomsday-display.doomsday-year > .doomsday-value",
);
yearElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset) => (selectedYear + offset).toString(),
);
});
// Display the doomsday weekday for the selected year
const doomsdayWeekdayElements = document.querySelectorAll(
".doomsday-display.doomsday-weekday > .doomsday-value",
);
const doomsdayDate = new Date(selectedYear, 2, febDoomsdayDay);
const doomsdayOfSelectedYear = doomsdayDate.getDay();
const doomsdayOfSelectedYearInText = weekdays[doomsdayOfSelectedYear];
doomsdayWeekdayElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset) => {
if (offset === 0) {
return doomsdayOfSelectedYearInText;
} else {
const adjustedDoomsday =
(doomsdayOfSelectedYear + offset) % 7;
return weekdays[adjustedDoomsday];
}
},
);
});
// Display the weekday number of the doomsday for the selected year
const doomsdayWeekdayNumberElements = document.querySelectorAll(
".doomsday-display.doomsday-weekday-number > .doomsday-value",
);
doomsdayWeekdayNumberElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset) => (doomsdayOfSelectedYear + offset) % 7,
).toString();
});
// Display the doomsday date for January and February
const janDoomsdayDay = isSelectedYearLeap ? 4 : 3;
const janDoomsdayDayElements = document.querySelectorAll(
".doomsday-display.doomsday-january-day > .doomsday-value",
);
janDoomsdayDayElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset) => (janDoomsdayDay + offset).toString(),
);
});
const febDoomsdayDayElements = document.querySelectorAll(
".doomsday-display.doomsday-february-day > .doomsday-value",
);
febDoomsdayDayElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset) => (febDoomsdayDay + offset).toString(),
);
});
}
currentYearInput?.addEventListener("input", update);
update();
</script>

View File

@ -0,0 +1,238 @@
---
import { cn } from "@/lib/utils";
export interface Props {
display:
| "weekday"
| "weekday-number"
| "weekday-of"
| "weekday-number-of"
| "year"
| "january-day"
| "february-day"
| "if-leap-year";
prefix?: string;
suffix?: string;
offset?: number;
resultModulo?: number;
value?: string;
valueAlt?: string;
valueClass?: string;
}
const {
display,
prefix,
suffix,
offset,
resultModulo,
valueClass: customClass,
value,
valueAlt,
} = Astro.props;
---
<span class={cn(`doomsday-display doomsday-${display}`)}
>{prefix}<span
class={cn("doomsday-value", customClass)}
data-offset={offset}
data-resultmodulo={resultModulo}
data-value={value}
data-valuealt={valueAlt}>...</span
>{suffix}</span
>
<script>
function isLeapYear(year: number) {
return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0;
}
function optionalModulo(value: number, modulo?: number): number {
if (modulo === undefined) {
return value;
}
return (value + modulo) % modulo;
}
function dateFromValueString(value: string, year: number): Date | null {
const parts = value.split(".");
if (parts.length !== 3) {
return null;
}
const [dayStr, monthStr, blank] = parts;
const day = parseInt(dayStr);
const month = parseInt(monthStr) - 1; // JavaScript months are 0-indexed
if (isNaN(day) || isNaN(month) || month < 0 || month > 11) {
return null;
}
const date = new Date(year, month, day);
return date;
}
function handleOffset<T>(
element: HTMLElement,
fn: (offset: number, modulo?: number) => T,
): T {
const offset = parseInt(element.dataset.offset || "0");
const resultModulo = element.dataset.resultmodulo
? parseInt(element.dataset.resultmodulo)
: undefined;
return fn(offset, resultModulo);
}
const weekdays = [
"Sunday",
"Monday",
"Tuesday",
"Wednesday",
"Thursday",
"Friday",
"Saturday",
];
const currentYearInput = document.getElementById(
"doomsday-year",
) as HTMLInputElement | null;
let firstUpdate = true;
function update() {
const selectedYear =
!firstUpdate && currentYearInput && currentYearInput.value
? parseInt(currentYearInput.value)
: new Date().getFullYear();
firstUpdate = false;
console.log("Selected Year:", selectedYear);
const isSelectedYearLeap = isLeapYear(selectedYear);
const febDoomsdayDay = 28 + (isSelectedYearLeap ? 1 : 0);
// Display the selected year
const yearElements = document.querySelectorAll(
".doomsday-display.doomsday-year > .doomsday-value",
);
yearElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset, modulo) =>
optionalModulo(selectedYear + offset, modulo).toString(),
);
});
// Display the doomsday weekday for the selected year
const doomsdayWeekdayElements = document.querySelectorAll(
".doomsday-display.doomsday-weekday > .doomsday-value",
);
const doomsdayDate = new Date(selectedYear, 2, febDoomsdayDay);
const doomsdayOfSelectedYear = doomsdayDate.getDay();
const doomsdayOfSelectedYearInText = weekdays[doomsdayOfSelectedYear];
doomsdayWeekdayElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset) => {
if (offset === 0) {
return doomsdayOfSelectedYearInText;
} else {
const adjustedDoomsday = optionalModulo(
doomsdayOfSelectedYear + offset,
7,
);
return weekdays[adjustedDoomsday];
}
},
);
});
// Display the weekday number of the doomsday for the selected year
const doomsdayWeekdayNumberElements = document.querySelectorAll(
".doomsday-display.doomsday-weekday-number > .doomsday-value",
);
doomsdayWeekdayNumberElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset) =>
optionalModulo(
doomsdayOfSelectedYear + offset,
7,
).toString(),
).toString();
});
// Display the doomsday date for January and February
const janDoomsdayDay = isSelectedYearLeap ? 4 : 3;
const janDoomsdayDayElements = document.querySelectorAll(
".doomsday-display.doomsday-january-day > .doomsday-value",
);
janDoomsdayDayElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset, modulo) =>
optionalModulo(janDoomsdayDay + offset, modulo).toString(),
);
});
const febDoomsdayDayElements = document.querySelectorAll(
".doomsday-display.doomsday-february-day > .doomsday-value",
);
febDoomsdayDayElements.forEach((element) => {
element.textContent = handleOffset(
element as HTMLElement,
(offset, modulo) =>
optionalModulo(febDoomsdayDay + offset, modulo).toString(),
);
});
// Weekday of a specific date
const weekdayOfElements = document.querySelectorAll(
".doomsday-display.doomsday-weekday-of > .doomsday-value",
);
weekdayOfElements.forEach((element) => {
const dateStr = (element as HTMLElement).dataset.value || "";
const date = dateFromValueString(dateStr, selectedYear);
if (date === null) {
element.textContent = "INVALID DATE";
element.classList.add("text-red-500");
return;
}
const weekday = date.getDay();
element.textContent = handleOffset(
element as HTMLElement,
(offset) => {
const adjustedWeekday = optionalModulo(weekday + offset, 7);
return weekdays[adjustedWeekday];
},
);
});
const weekdayNumberOfElements = document.querySelectorAll(
".doomsday-display.doomsday-weekday-number-of > .doomsday-value",
);
weekdayNumberOfElements.forEach((element) => {
const dateStr = (element as HTMLElement).dataset.value || "";
const date = dateFromValueString(dateStr, selectedYear);
if (date === null) {
element.textContent = "INVALID DATE";
element.classList.add("text-red-500");
return;
}
const weekday = date.getDay();
element.textContent = handleOffset(
element as HTMLElement,
(offset, modulo) => {
const adjustedWeekday = optionalModulo(
weekday + offset,
modulo,
);
return adjustedWeekday.toString();
},
);
});
// Conditional on the leap year status
const ifLeapYearElements = document.querySelectorAll(
".doomsday-display.doomsday-if-leap-year > .doomsday-value",
);
ifLeapYearElements.forEach((element) => {
element.textContent = isSelectedYearLeap
? (element as HTMLElement).dataset.value || ""
: (element as HTMLElement).dataset.valuealt || "";
});
}
currentYearInput?.addEventListener("change", update);
update();
</script>

View File

@ -11,4 +11,10 @@
"doomsday-year", "doomsday-year",
) as HTMLInputElement; ) as HTMLInputElement;
currentYearInput.value = new Date().getFullYear().toString(); currentYearInput.value = new Date().getFullYear().toString();
currentYearInput.addEventListener("change", () => {
const year = parseInt(currentYearInput.value);
if (isNaN(year) || year < 1583) {
currentYearInput.value = "1583";
}
});
</script> </script>

View File

@ -1,41 +1,141 @@
--- ---
title: "Doomsday Algorithm" title: "Doomsday Algorithm"
summary: How to compute the day of the week of an arbitrary date in your head. summary: How to compute the day of the week of an arbitrary date in your head.
date: 2026-03-19 date: 2026-03-20
tags: tags:
- Math Trick - Math Trick
--- ---
import DynamicDoomsdayDisplay from "@/components/blog/content/doomsday-algorithm/DynamicDoomsdayDisplay.astro"; import DynamicDoomsdayDisplay from "./DynamicDoomsdayDisplay.astro";
import DynamicDoomsdayYearSelector from "@/components/blog/content/doomsday-algorithm/DynamicDoomsdayYearSelector.astro"; import DynamicDoomsdayYearSelector from "./DynamicDoomsdayYearSelector.astro";
Generally, the idea is that there are certain dates in a year, that always fall on the same day of the week. We call those dates Doomsdays and there are rules for finding the Doomsday of every month. We get started with the easiest months: Generally, the idea is that there are certain dates in a year, that always fall on the same day of the week.
We call those dates Doomsdays and there are rules for finding the Doomsday of every month.
From these Doomdays, we can determine the weekday of any given date using only addition & subtraction, using multiples of 7.
For this trick you should be able to do this comfortable in your head. We get started with the easiest months:
## (Most) Even Months ## (Most) Even Months
We can use (almost) any even month for determining the Doomsday of a given year. For any even-numbered month except February, the same day is the Doomsday as the months number. This means: We can use (almost) any even month for determining the Doomsday of a given year. For any even-numbered month except February,
the same day is the Doomsday as the months number. This means:
- the 4th of April (4) is a Doomsday, - the 4th of April (4) is a Doomsday,
- the 6th of June (6) is a Doomsday, - the 6th of June (6) is a Doomsday,
- the 8th of August (8) is a Doomsday,
- the 10th of October (10) is a Doomsday, - the 10th of October (10) is a Doomsday,
- the 12th of December (12) is a Doomsday. - the 12th of December (12) is a Doomsday.
Generally, for the Nth _even_ month, the Nth day is a Doomsday. Generally, for the Nth _even_ month, the Nth day is a Doomsday.
We can use this for our first weekday calculation. Let's ask ourselves, what weekday is Halloween (31st of October) this year? We can use this for our first weekday calculation. Let's ask ourselves, what weekday is Halloween (31st of October) <DynamicDoomsdayDisplay display="year" suffix="?" />
We know that the 10th of October is a <DynamicDoomsdayDisplay display="weekday" /> because it is a Doomsday. Calculating 31 - 10 = 21, we know that it is exactly three weeks afterward a Doomsday. We know that the 10th of October is a <DynamicDoomsdayDisplay display="weekday" /> because it is a Doomsday.
Therefore, **Halloween is a Doomsday**. This year, Halloween falls on a <DynamicDoomsdayDisplay display="weekday" suffix="." /> Calculating 31 - 10 = 21, we know that it is exactly three weeks afterward a Doomsday.
Therefore, **Halloween is a Doomsday**. In <DynamicDoomsdayDisplay display="year" suffix="," /> Halloween falls on a <DynamicDoomsdayDisplay display="weekday" suffix="." />
To make finding the weekday easier, we can represent the weekdays as numbers ranging from 0 (Sunday) to 6 (Saturday). The number of the weekday of any given date can be computed by adding the number of the Doomsday weekday and the offset to the nearest Doomsday and then computing modulo 7 of that value. To make finding the weekday easier, we can represent the weekdays as numbers ranging from 0 (Sunday) to 6 (Saturday).
The number of the weekday of any given date can be computed by adding the number of the Doomsday weekday and the offset to the nearest Doomsday
and then computing modulo 7 of that value.
Let's take a look at the remaining even month: Let's try again with the [German Unity Day](https://en.wikipedia.org/wiki/German_Unity_Day) (3rd of October) <DynamicDoomsdayDisplay display="year" suffix="." /> We use the Doomsday of October, which is the 10th.
Calculating 3 - 10 = -7, we know that it is exactly one week before a Doomsday. Therefore, the German Unity Day is exactly one week before a Doomsday. **German Unity Day always falls on the same weekday as the Doomsday**.
Let's take a look at the last remaining even month:
## February ## February
The Doomsday is always the last day of february, e.g. **February 28 or 29**. The Doomsday is always the last day of february, e.g. **February 28 or 29**.
In <DynamicDoomsdayDisplay display="year" suffix="," /> February <DynamicDoomsdayDisplay display="february-day" /> is a <DynamicDoomsdayDisplay display="weekday" valueClass="font-bold" suffix="." />
For <DynamicDoomsdayDisplay display="year" suffix="," /> February <DynamicDoomsdayDisplay display="february-day" /> is a <DynamicDoomsdayDisplay display="weekday" valueClass="font-bold" suffix="." /> Again, we want to compute the weekday of a given date, let's say Groundhog Day (2nd of February) <DynamicDoomsdayDisplay display="year" suffix="." />
We know that the Doomsday is the <DynamicDoomsdayDisplay display="february-day" suffix="th" /> of February, so we compute
2 - <DynamicDoomsdayDisplay display="february-day" /> = <DynamicDoomsdayDisplay display="february-day" offset={-2} prefix="-" /> as we are going
backwards three weeks (21 days) and then <DynamicDoomsdayDisplay display="february-day" offset={-2} resultModulo={7} /> more.
<DynamicDoomsdayDisplay display="february-day" offset={-2} prefix="-" /> modulo 7 is <DynamicDoomsdayDisplay display="february-day" offset={2} resultModulo={7} suffix="." />
Going forward <DynamicDoomsdayDisplay display="february-day" offset={2} resultModulo={7} /> days is the same as going backwards <DynamicDoomsdayDisplay display="february-day" offset={-2} resultModulo={7} /> days
because of the cyclic nature of the week. Adding this to the Doomsday <DynamicDoomsdayDisplay display="weekday" />
<DynamicDoomsdayDisplay display="weekday-number" prefix="(" suffix=")" /> modulo 7, we get <DynamicDoomsdayDisplay display="weekday-number-of" value="02.02." suffix="," />
e.g. <DynamicDoomsdayDisplay display="weekday-of" value="02.02." suffix="." />
Afterwards ## Some Odd Months
Odd months do not have such a simple rule for their Doomsday as even months. May, July, September, and November each have a "partner-month" where the Doomsday is the number of the partner-month.
For this, a simple mnemonic exists:
> I work 9-5 at 7-11.
From this, we can easily deduce what the partner-months may be and remember the following Doomsdays:
- the 9th of May (5) is a Doomsday,
- the 11th of July (7) is a Doomsday,
- the 5th of September (9) is a Doomsday,
- the 7th of November (11) is a Doomsday.
For example, to compute the weekday of the [International Day of Peace](https://en.wikipedia.org/wiki/International_Day_of_Peace) (21st of September) <DynamicDoomsdayDisplay display="year" suffix="," /> we can use the Doomsday of September, which is the 5th.
Calculating 21 - 5 = 16, we know that it is exactly two weeks and two days after a Doomsday. Therefore, **the International Day of Peace is two days after a Doomsday**.
In <DynamicDoomsdayDisplay display="year" suffix="," /> the International Day of Peace falls on a <DynamicDoomsdayDisplay display="weekday-of" value="21.09." suffix="." />
## March & January
There are two memorable dates in March that can be used as Doomsdays: either the 0th of March (which is the same as the last day of February) or the 14th of March ([Pi Day](https://en.wikipedia.org/wiki/Pi_Day)).
January is a bit more difficult, as it lays before the leap day in February. The Doomsday of January is the 3rd in common years and the 4th in leap years. Another way would be to think of January belonging to the previous year, where the Doomsday of the previous year is on the 2nd of January.
What was New Year's Day (1st of January) <DynamicDoomsdayDisplay display="year" suffix="?" /> We can use the nearest Doomsday: January <DynamicDoomsdayDisplay display="if-leap-year" value="4th" valueAlt="3rd" suffix="." />
<DynamicDoomsdayDisplay display="january-day"/> days before the Doomsday <DynamicDoomsdayDisplay display="weekday" prefix="(" suffix=")" /> is a <DynamicDoomsdayDisplay display="weekday-of" value="01.01." suffix="." />
Now, we know how to compute the weekday of any given date, but we still need to find the Doomsday of a given year.
## Computing the Doomsday of a Year
Let's take a look at how to compute the Doomsday of a given year from the Doomsday of the century. I am going to present two methods -- the first one is more intuitive and easier to remember, while the second one is more mathematically pure.
First, we take the last two digits of the year. If this number is odd, we add 11 to it. Then, we divide the number by 2. If the result is odd, we add 11 again.
Finally, we take 7 minus modulo 7 of the result and count forward that many days from the Doomsday of the century. The resulting weekday is the Doomsday of the year.
This algorithm can be remembered with the following flowchart:
```mermaid
flowchart TD
B[Let T = last two digits of year] --> C{Is T odd?}
C -- Yes --> D[T = T + 11]
C -- No --> F
D --> F[T = T / 2]
F --> G{Is T odd?}
G -- Yes --> H[T = T + 11]
G -- No --> J
H --> J["T = 7 - (T mod 7)"]
J --> K[Count forward T days from Doomsday of the century]
K --> L[Doomsday of the year]
```
The second method is more mathematical and follows the steps:
1. Take the last two digits of the year and divide by 12. Let A be the quotient and B be the remainder.
2. Divide B by 4 and let C be the quotient.
3. Take the sum of the Doomsday of the century, A, B, and C. The result modulo 7 is the Doomsday of the year.
For example, let's compute the Doomsday of the year 1999. The Doomsday of the 1900s is a Wednesday (3).
The last two digits of the year are 99. Dividing 99 by 12 gives a quotient of 8 and a remainder of 3.
Dividing the remainder (3) by 4 gives a quotient of 0. Adding these values together gives us 3 + 8 + 3 + 0 = 14.
Taking this result modulo 7 gives us 0, which corresponds to Sunday. Therefore, the Doomsday of the year 1999 is a Sunday.
To showcase the first method, let's compute the Doomsday of the year 1975. Remember, the Doomsday of the 1900 is a Wednesday (3).
The last two digits of the year are 75, which is odd, so we add 11 to get 86. Then we divide 86 by 2 to get 43, which is odd, so we add 11 again to get 54.
Finally, we take 7 minus 54 modulo 7, which is 7 minus 5 and gives us 2. Counting forward 2 days from Wednesday (3) gives us Friday (5).
## Increasing Speed by Memorization
By memorizing the years in a century that have the same Doomsday as the century's Doomsday, we can increase our speed significantly.
<DynamicDoomsdayYearSelector /> <DynamicDoomsdayYearSelector />
## Sources
- https://en.wikipedia.org/wiki/Doomsday_rule
- https://www.rudy.ca/doomsday.html
- [Conway's original paper: "Tomorrow is the day after Doomsday"](https://web.archive.org/web/20240907031643/https://www.archim.org.uk/eureka/archive/Eureka-36.pdf)