From 7a901581393c2981a11168161ccee1cd5e885f48 Mon Sep 17 00:00:00 2001 From: Lucas Winther Date: Tue, 18 Aug 2026 21:48:48 +0200 Subject: [PATCH] fix: print the date the countdown is actually counting to MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The detail sheet formatted the stored ISO, so a day-precision end rendered as 00:00Z — the previous day for every reader west of UTC, and now a different day from the timer sitting beside it. Both dates come off the clock instead, which resolves them the same way. The note under them said the end was "accurate to the day only" and left it there. It can say where the count actually lands, and should: a reader deciding whether to log in tonight wants the reset, not a shrug. It still says this is a reading rather than a time the source printed. REGION_LABEL moves next to the region table it names, which is also how the note gets "Europe" rather than the raw id. Co-Authored-By: Claude Opus 5 (1M context) --- src/client/components/Controls.tsx | 9 ++++----- src/client/components/EventDetail.tsx | 21 +++++++++++++++------ src/shared/time.ts | 19 +++++++++++++++++-- 3 files changed, 36 insertions(+), 13 deletions(-) diff --git a/src/client/components/Controls.tsx b/src/client/components/Controls.tsx index 66ba1b0..d308113 100644 --- a/src/client/components/Controls.tsx +++ b/src/client/components/Controls.tsx @@ -1,14 +1,13 @@ import type { LaneId } from "../../shared/custom.ts"; import type { Region } from "../../shared/schema.ts"; +import { REGION_LABEL } from "../../shared/time.ts"; import { useGameMeta } from "../state/gameMeta.tsx"; import type { Prefs } from "../state/usePrefs.ts"; import { YourOwn } from "./YourOwn.tsx"; -const REGIONS: Array<{ id: Region; label: string }> = [ - { id: "america", label: "America" }, - { id: "europe", label: "Europe" }, - { id: "asia", label: "Asia" }, -]; +const REGIONS: Array<{ id: Region; label: string }> = ( + ["america", "europe", "asia"] as const +).map((id) => ({ id, label: REGION_LABEL[id] })); export function Controls({ games, diff --git a/src/client/components/EventDetail.tsx b/src/client/components/EventDetail.tsx index 38176c8..febf37e 100644 --- a/src/client/components/EventDetail.tsx +++ b/src/client/components/EventDetail.tsx @@ -8,7 +8,11 @@ import { } from "../../shared/custom.ts"; import type { EventDraft } from "../state/useCustom.ts"; import { EventForm } from "./CustomForms.tsx"; -import { formatAbsolute, formatRemaining } from "../../shared/time.ts"; +import { + formatAbsolute, + formatRemaining, + REGION_LABEL, +} from "../../shared/time.ts"; import type { RowEvent } from "./EventRow.tsx"; import { pressure, pressureReason, type Effort } from "../../shared/effort.ts"; import type { Status } from "../state/useProgress.ts"; @@ -132,14 +136,17 @@ export function EventDetail({
+ {/* Off the clock, not off the event: a day-precision boundary is + resolved to the game's reset there, and printing the stored + 00:00Z instead would name a different day to the countdown. */} - {formatAbsolute(event.startsAt, event.startPrecision === "exact")} + {formatAbsolute(clock.startsMs, event.startPrecision === "exact")} - {event.endsAt === null ? ( + {clock.endsMs === null ? ( Not announced ) : ( - formatAbsolute(event.endsAt, event.endPrecision === "exact") + formatAbsolute(clock.endsMs, event.endPrecision === "exact") )} @@ -267,8 +274,10 @@ export function EventDetail({ {event.endPrecision === "day" && event.endsAt !== null && (

- The source gave a date but no time of day, so this end is accurate to - the day only. Check in-game before the last hours. + The source gave a date but no time of day, so this counts down to + that day's {REGION_LABEL[region]} server reset — where these usually land, but a + reading rather than a stated time. Check in-game before the last + hours.

)} diff --git a/src/shared/time.ts b/src/shared/time.ts index 430b394..67bbbfc 100644 --- a/src/shared/time.ts +++ b/src/shared/time.ts @@ -21,6 +21,13 @@ export const REGION_RESET_UTC_OFFSET: Record = { europe: 1, }; +/** What a region is called when the reader is shown one. */ +export const REGION_LABEL: Record = { + america: "America", + europe: "Europe", + asia: "Asia", +}; + /** * Gacha servers roll the day at 04:00 local server time, not midnight — a * player finishing at 02:00 is still on the previous day's dailies. Getting @@ -224,8 +231,16 @@ export function formatRemaining(msRemaining: number): string { return `${seconds}s`; } -/** Absolute date for the detail view, in the reader's own timezone. */ -export function formatAbsolute(iso: string, withTime: boolean): string { +/** + * Absolute date for the detail view, in the reader's own timezone. + * + * Takes an instant rather than only an ISO string so a caller with a resolved + * boundary can print the one the countdown is counting to. A day-precision date + * read straight off the event says 00:00Z, which renders as the *previous* day + * to every reader west of UTC — the sheet would then name one day while the + * timer beside it ran to another. + */ +export function formatAbsolute(iso: string | number, withTime: boolean): string { const d = new Date(iso); const date = d.toLocaleDateString(undefined, { weekday: "short",