feat: infer default time format from navigator.language

This commit is contained in:
Nicolas Meienberger 2026-03-30 18:44:26 +02:00
parent f89b8c3b52
commit e55ffccd21
3 changed files with 53 additions and 3 deletions

View file

@ -8,6 +8,7 @@ import {
formatShortDateTime,
formatTime,
formatTimeAgo,
inferDateTimePreferences,
} from "../datetime";
afterEach(() => {
@ -89,6 +90,14 @@ describe("datetime formatters", () => {
expect(formatTime(sampleDate, { locale: "en-US", timeZone: "UTC", timeFormat })).toBe(expected);
});
test.each([
["en-US", { dateFormat: "MM/DD/YYYY", timeFormat: "12h" }],
["en-GB", { dateFormat: "DD/MM/YYYY", timeFormat: "24h" }],
["ja-JP", { dateFormat: "YYYY/MM/DD", timeFormat: "24h" }],
] as const)("infers date and time preferences for %s", (locale, expected) => {
expect(inferDateTimePreferences(locale)).toEqual(expected);
});
test("formats combined values with custom date and time preferences", () => {
expect(
formatDateTime(sampleDate, {

View file

@ -12,6 +12,8 @@ export const TIME_FORMATS = ["12h", "24h"] as const;
export type TimeFormatPreference = (typeof TIME_FORMATS)[number];
export const DEFAULT_TIME_FORMAT: TimeFormatPreference = "12h";
const BROWSER_PREFERENCE_SAMPLE_DATE = new Date(Date.UTC(2006, 0, 2, 15, 4, 5));
const DATE_PART_ORDERS = {
"MM/DD/YYYY": ["month", "day", "year"],
"DD/MM/YYYY": ["day", "month", "year"],
@ -109,6 +111,43 @@ function formatConfiguredTime(date: Date, options: DateFormatOptions) {
}).format(date);
}
export function inferDateTimePreferences(locale?: string) {
const dateOrder = getDateTimeFormat(locale, undefined, {
month: "numeric",
day: "numeric",
year: "numeric",
})
.formatToParts(BROWSER_PREFERENCE_SAMPLE_DATE)
.flatMap((part) => {
if (part.type === "year" || part.type === "month" || part.type === "day") {
return [part.type];
}
return [];
})
.join("/");
let dateFormat = DEFAULT_DATE_FORMAT;
if (dateOrder === "day/month/year") {
dateFormat = "DD/MM/YYYY";
} else if (dateOrder === "year/month/day") {
dateFormat = "YYYY/MM/DD";
}
let timeFormat: TimeFormatPreference = "12h";
const hour12 = getDateTimeFormat(locale, undefined, { hour: "numeric" }).resolvedOptions().hour12;
if (hour12 === false) {
timeFormat = "24h";
}
return {
dateFormat,
timeFormat,
};
}
// 1/10/2026, 2:30 PM
export function formatDateTime(date: DateInput, options: DateFormatOptions = {}): string {
return formatValidDate(

View file

@ -20,7 +20,7 @@ import { useState } from "react";
import { useNavigate } from "@tanstack/react-router";
import { normalizeUsername } from "~/lib/username";
import { z } from "zod";
import { DEFAULT_DATE_FORMAT, DEFAULT_TIME_FORMAT } from "~/client/lib/datetime";
import { inferDateTimePreferences } from "~/client/lib/datetime";
export const clientMiddleware = [authMiddleware];
@ -59,10 +59,12 @@ export function OnboardingPage() {
return;
}
const { dateFormat, timeFormat } = inferDateTimePreferences(navigator.language);
const { data, error } = await authClient.signUp.email({
username: normalizeUsername(values.username),
dateFormat: DEFAULT_DATE_FORMAT,
timeFormat: DEFAULT_TIME_FORMAT,
dateFormat,
timeFormat,
password: values.password,
email: values.email.toLowerCase().trim(),
name: values.username,