Download superlog/apps/web/src/timeFormat.ts from smlflg/Experimente: direct link, hf CLI and curl.
- Browser
- Download file 2.47 kB
-
https://huggingface.co/smlflg/Experimente/resolve/main/superlog/apps/web/src/timeFormat.ts
- Command line
-
hf download hf://smlflg/Experimente/superlog/apps/web/src/timeFormat.ts
-
curl -L -o timeFormat.ts https://huggingface.co/smlflg/Experimente/resolve/main/superlog/apps/web/src/timeFormat.ts
2.47 kB
| // Helpers for displaying ClickHouse-stored timestamps (UTC) in the user's local | |
| // timezone. ClickHouse returns DateTime / DateTime64 as | |
| // "YYYY-MM-DD HH:MM:SS[.fraction]" — a naive string with no zone. The server is | |
| // UTC, so we parse as UTC and reformat in local time. | |
| function parseChUtc(s: string): { date: Date; frac: string } | null { | |
| if (!s) return null; | |
| const dot = s.indexOf("."); | |
| const head = dot === -1 ? s : s.slice(0, dot); | |
| const frac = dot === -1 ? "" : s.slice(dot + 1); | |
| // Accept both "YYYY-MM-DD HH:MM:SS" and ISO "YYYY-MM-DDTHH:MM:SS". | |
| const iso = head.replace(" ", "T") + "Z"; | |
| const d = new Date(iso); | |
| if (Number.isNaN(d.getTime())) return null; | |
| return { date: d, frac }; | |
| } | |
| function pad2(n: number): string { | |
| return n < 10 ? `0${n}` : `${n}`; | |
| } | |
| // "YYYY-MM-DD HH:MM:SS.ff" in local tz, fraction rounded to 2 digits. | |
| export function formatLocalTimestampMs(s: string): string { | |
| const p = parseChUtc(s); | |
| if (!p) return s; | |
| const { date, frac } = p; | |
| const head = | |
| `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ` + | |
| `${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}`; | |
| const fracN = Number(`0.${frac || "0"}`); | |
| const f = Number.isFinite(fracN) | |
| ? Math.round(fracN * 100).toString().padStart(2, "0") | |
| : "00"; | |
| return `${head}.${f}`; | |
| } | |
| // "YYYY-MM-DD HH:MM:SS" in local tz (no fractional seconds). | |
| export function formatLocalTimestamp(s: string): string { | |
| const p = parseChUtc(s); | |
| if (!p) return s; | |
| const { date } = p; | |
| return ( | |
| `${date.getFullYear()}-${pad2(date.getMonth() + 1)}-${pad2(date.getDate())} ` + | |
| `${pad2(date.getHours())}:${pad2(date.getMinutes())}:${pad2(date.getSeconds())}` | |
| ); | |
| } | |
| // "HH:MM" in local tz — for chart axis ticks. | |
| export function formatLocalHm(s: string): string { | |
| const p = parseChUtc(s); | |
| if (!p) return s.length >= 16 ? s.slice(11, 16) : s; | |
| const { date } = p; | |
| return `${pad2(date.getHours())}:${pad2(date.getMinutes())}`; | |
| } | |
| let cachedTzAbbr: string | null = null; | |
| export function localTzAbbr(): string { | |
| if (cachedTzAbbr) return cachedTzAbbr; | |
| try { | |
| const parts = new Intl.DateTimeFormat(undefined, { | |
| timeZoneName: "short", | |
| }).formatToParts(new Date()); | |
| const tz = parts.find((p) => p.type === "timeZoneName")?.value; | |
| cachedTzAbbr = tz || Intl.DateTimeFormat().resolvedOptions().timeZone; | |
| } catch { | |
| cachedTzAbbr = "local"; | |
| } | |
| return cachedTzAbbr!; | |
| } | |