Picking a clock picks its separator too

24-hour read as 13.45 in Denmark, because that is how Danish writes a
clock and toLocaleTimeString was doing as it was told. But somebody who
leaves "follow the region" and picks 24-hour has just said they want the
region to stop deciding — and they mean 13:45.

So the two explicit modes build the string from formatToParts and pin the
mark between the hour and the minute. Only that one literal is replaced:
everything else stays the locale's, which is why Japanese keeps 午後 in
front of it and English keeps its lowercase pm after. 12-hour got the
same for free — it had the identical 01.45 pm.

Auto is left alone. A setting that says to follow the region has no
business arguing with it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
tajniak81
2026-09-03 20:29:49 +02:00
co-authored by Claude Opus 5
parent 4d51a34c44
commit 263d35c688
+21 -3
View File
@@ -92,9 +92,27 @@ export function formatTime(value) {
const d = value instanceof Date ? value : new Date(value); const d = value instanceof Date ? value : new Date(value);
if (isNaN(d)) return "—"; if (isNaN(d)) return "—";
const opts = { hour: "2-digit", minute: "2-digit" }; const opts = { hour: "2-digit", minute: "2-digit" };
if (prefs.timeFormat === "24") opts.hourCycle = "h23"; const mode = prefs.timeFormat;
else if (prefs.timeFormat === "12") opts.hourCycle = "h12"; if (mode !== "24" && mode !== "12") {
return d.toLocaleTimeString(prefs.locale || undefined, opts); // Auto is the region's, whole: 13.45 is how Danish writes a clock, and a
// setting that says "follow the region" has no business arguing with it.
return d.toLocaleTimeString(prefs.locale || undefined, opts);
}
// Asking for a clock outright is asking for its separator too. Somebody who
// picked "24-hour" means 13:45, not the 13.45 their region would have written
// — the point of leaving auto was to stop the region deciding. Only the mark
// between the hour and the minute is pinned: the rest is still the locale's,
// including whether there is an am/pm marker, what it reads and where it sits.
opts.hourCycle = mode === "24" ? "h23" : "h12";
const parts = new Intl.DateTimeFormat(prefs.locale || undefined, opts).formatToParts(d);
return parts
.map((p, i) =>
p.type === "literal" && parts[i - 1]?.type === "hour" && parts[i + 1]?.type === "minute"
? ":"
: p.value
)
.join("");
} }
// Every number we render goes through here so the grouping separator follows // Every number we render goes through here so the grouping separator follows