M33: enforce booking readiness workflow

This commit is contained in:
NuklearRabbit
2026-08-10 22:23:11 +02:00
parent be33b46228
commit 82a933f6cd
12 changed files with 273 additions and 43 deletions
+46
View File
@@ -0,0 +1,46 @@
const BRUSSELS_TIME_ZONE = "Europe/Brussels";
const partsFormatter = new Intl.DateTimeFormat("en-CA", {
timeZone: BRUSSELS_TIME_ZONE,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
hourCycle: "h23",
});
function partsAt(value: Date): Record<string, string> {
return Object.fromEntries(
partsFormatter.formatToParts(value)
.filter((part) => part.type !== "literal")
.map((part) => [part.type, part.value]),
);
}
export function toBrusselsDateTimeLocal(value: Date): string {
const parts = partsAt(value);
return `${parts.year}-${parts.month}-${parts.day}T${parts.hour}:${parts.minute}`;
}
export function brusselsDateTimeFromNow(hours: number): string {
const value = new Date(Date.now() + hours * 60 * 60 * 1000);
value.setUTCMinutes(0, 0, 0);
return toBrusselsDateTimeLocal(value);
}
/** Convert a Fleet Ops Europe/Brussels wall-clock value to an unambiguous UTC instant. */
export function brusselsLocalToIso(value: string): string {
const match = /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2})$/.exec(value);
if (!match) throw new Error("Invalid Brussels date-time");
const [, year, month, day, hour, minute] = match;
const wallClockUtc = Date.UTC(+year, +month - 1, +day, +hour, +minute);
let candidate = wallClockUtc;
for (let iteration = 0; iteration < 3; iteration += 1) {
const parts = partsAt(new Date(candidate));
const represented = Date.UTC(+parts.year, +parts.month - 1, +parts.day, +parts.hour, +parts.minute);
candidate += wallClockUtc - represented;
}
return new Date(candidate).toISOString();
}