doomsday: beginnings

This commit is contained in:
Moritz Hölting 2026-03-20 00:09:31 +01:00
parent e4eef33c2a
commit 72cbae88e0
4 changed files with 219 additions and 19 deletions

View File

@ -10,25 +10,34 @@ import icon from "astro-icon";
// https://astro.build/config
export default defineConfig({
site: "https://hoelting.dev",
trailingSlash: "always",
site: "https://hoelting.dev",
trailingSlash: "always",
integrations: [mdx(), sitemap(), icon(), solidJs(), matomo({
enabled: import.meta.env.PROD, // only enable in production
url: "https://analytics.hoelting.dev",
siteId: 3,
disableCookies: true,
enableCrossDomainLinking: true,
domains: ["*.hoelting.dev", "*.www.hoelting.dev"],
respectDoNotTrack: true,
})],
integrations: [
mdx(),
sitemap(),
icon(),
solidJs(),
matomo({
enabled: import.meta.env.PROD, // only enable in production
url: "https://analytics.hoelting.dev",
siteId: 3,
disableCookies: true,
enableCrossDomainLinking: true,
domains: ["*.hoelting.dev", "*.www.hoelting.dev"],
respectDoNotTrack: true,
}),
],
markdown: {
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
},
markdown: {
remarkPlugins: [remarkMath],
rehypePlugins: [rehypeKatex],
},
vite: {
plugins: [tailwindcss({ applyBaseStyles: false })],
},
});
vite: {
plugins: [tailwindcss({ applyBaseStyles: false })],
server: {
watch: {},
},
},
});

View File

@ -0,0 +1,136 @@
---
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,14 @@
<input
type="number"
name="doomsday-year"
id="doomsday-year"
min="1583"
class="w-16"
/>
<script>
const currentYearInput = document.getElementById(
"doomsday-year",
) as HTMLInputElement;
currentYearInput.value = new Date().getFullYear().toString();
</script>

View File

@ -0,0 +1,41 @@
---
title: "Doomsday Algorithm"
summary: How to compute the day of the week of an arbitrary date in your head.
date: 2026-03-19
tags:
- Math Trick
---
import DynamicDoomsdayDisplay from "@/components/blog/content/doomsday-algorithm/DynamicDoomsdayDisplay.astro";
import DynamicDoomsdayYearSelector from "@/components/blog/content/doomsday-algorithm/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:
## (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:
- the 4th of April (4) is a Doomsday,
- the 6th of June (6) is a Doomsday,
- the 10th of October (10) is a Doomsday,
- the 12th of December (12) 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 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.
Therefore, **Halloween is a Doomsday**. This year, 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.
Let's take a look at the remaining even month:
## February
The Doomsday is always the last day of february, e.g. **February 28 or 29**.
For <DynamicDoomsdayDisplay display="year" suffix="," /> February <DynamicDoomsdayDisplay display="february-day" /> is a <DynamicDoomsdayDisplay display="weekday" valueClass="font-bold" suffix="." />
Afterwards
<DynamicDoomsdayYearSelector />