Skip to content

Commit c36cc46

Browse files
committed
fix: show dashboard log timestamps in server timezone
Fixes #725
1 parent b7e59c0 commit c36cc46

2 files changed

Lines changed: 15 additions & 8 deletions

File tree

gui/src/pages/Logs.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -280,12 +280,12 @@ function statusColor(status: number): string {
280280
return "var(--amber)";
281281
}
282282

283-
function formatLogTimestamp(ts: number, localeTag?: string): string {
284-
return new Date(ts).toLocaleTimeString(localeTag);
283+
function formatLogTimestamp(ts: number, localeTag?: string, timeZone?: string): string {
284+
return new Date(ts).toLocaleTimeString(localeTag, timeZone ? { timeZone } : undefined);
285285
}
286286

287-
function formatLogDateTime(ts: number, localeTag?: string): string {
288-
return new Date(ts).toLocaleString(localeTag);
287+
function formatLogDateTime(ts: number, localeTag?: string, timeZone?: string): string {
288+
return new Date(ts).toLocaleString(localeTag, timeZone ? { timeZone } : undefined);
289289
}
290290

291291
function modelTitle(log: LogEntry): string {
@@ -333,6 +333,7 @@ export default function Logs({ apiBase }: { apiBase: string }) {
333333
const { t, locale } = useI18n();
334334
const cachedLogs = readSessionListCache<LogEntry[]>(logsCacheKey(apiBase));
335335
const [logs, setLogs] = useState<LogEntry[]>(() => cachedLogs ?? []);
336+
const [serverTimeZone, setServerTimeZone] = useState<string | undefined>();
336337
const [loading, setLoading] = useState(() => !(cachedLogs && cachedLogs.length > 0));
337338
const [error, setError] = useState<string | null>(null);
338339
const [autoRefresh, setAutoRefresh] = useState(true);
@@ -370,8 +371,11 @@ export default function Logs({ apiBase }: { apiBase: string }) {
370371
try {
371372
const res = await fetch(`${apiBase}/api/logs?limit=2000`);
372373
if (!res.ok) throw new Error(`${res.status} ${res.statusText}`.trim());
373-
const body = await res.json() as LogEntry[] | { logs?: LogEntry[] };
374+
const body = await res.json() as LogEntry[] | { logs?: LogEntry[]; timeZone?: string };
374375
const next = Array.isArray(body) ? body : (body.logs ?? []);
376+
if (!Array.isArray(body) && typeof body.timeZone === "string" && body.timeZone.trim()) {
377+
setServerTimeZone(body.timeZone.trim());
378+
}
375379
setLogs(next);
376380
writeSessionListCache(logsCacheKey(apiBase), next);
377381
setError(null);
@@ -592,7 +596,7 @@ export default function Logs({ apiBase }: { apiBase: string }) {
592596
data-index={virtualRow.index}
593597
ref={rowVirtualizer.measureElement}
594598
>
595-
<td className="muted mono">{formatLogTimestamp(log.timestamp, localeTag)}</td>
599+
<td className="muted mono">{formatLogTimestamp(log.timestamp, localeTag, serverTimeZone)}</td>
596600
<td className="num mono log-col-tokens" title={tokensTitle(log, t)}>
597601
{(() => {
598602
const tokenTotal = displayContextTokenTotal(log);
@@ -679,6 +683,7 @@ export default function Logs({ apiBase }: { apiBase: string }) {
679683
detailInfo={detailInfo}
680684
localeCode={locale}
681685
localeTag={localeTag}
686+
serverTimeZone={serverTimeZone}
682687
t={t}
683688
onClose={() => setDetail(null)}
684689
onFilterConversation={id => {
@@ -704,12 +709,13 @@ function useModalDialog(open: boolean) {
704709
}
705710

706711
function LogDetailDialog({
707-
detail, detailInfo, localeCode, localeTag, t, onClose, onFilterConversation,
712+
detail, detailInfo, localeCode, localeTag, serverTimeZone, t, onClose, onFilterConversation,
708713
}: {
709714
detail: LogEntry;
710715
detailInfo: ReturnType<typeof statusCodeInfo> | null;
711716
localeCode: string;
712717
localeTag?: string;
718+
serverTimeZone?: string;
713719
t: TFn;
714720
onClose: () => void;
715721
onFilterConversation?: (conversationId: string) => void;
@@ -751,7 +757,7 @@ function LogDetailDialog({
751757
<section className="log-detail-section" aria-labelledby="log-detail-basic">
752758
<h4 id="log-detail-basic" className="log-detail-section-title">{t("logs.detail.section.basic")}</h4>
753759
<div className="log-detail-grid">
754-
<span className="muted">{t("logs.col.time")}</span><span className="mono">{formatLogDateTime(detail.timestamp, localeTag)}</span>
760+
<span className="muted">{t("logs.col.time")}</span><span className="mono">{formatLogDateTime(detail.timestamp, localeTag, serverTimeZone)}</span>
755761
<span className="muted">{t("logs.col.request")}</span>
756762
<span className="log-detail-request-row">
757763
<span className="mono log-detail-break">{detail.requestId ?? "\u2014"}</span>

src/server/management/config-routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ export async function handleConfigRoutes(ctx: ManagementContext): Promise<Respon
110110
);
111111
}
112112
return jsonResponse({
113+
timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
113114
codexAutoStart: codexAutoStartEnabled(config),
114115
port: config.port,
115116
hostname: config.hostname ?? "127.0.0.1",

0 commit comments

Comments
 (0)