From 79d00e20db8d5c9a8b30dfb0c835b4e895c6f6fb Mon Sep 17 00:00:00 2001 From: Tyler Yust Date: Tue, 3 Feb 2026 20:42:33 -0800 Subject: [PATCH] UI: handle future timestamps in formatAgo --- ui/src/ui/format.test.ts | 35 +++++++++++++++++++++++++++++++++-- ui/src/ui/format.ts | 15 +++++++-------- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/ui/src/ui/format.test.ts b/ui/src/ui/format.test.ts index cc992ea09f..281651357d 100644 --- a/ui/src/ui/format.test.ts +++ b/ui/src/ui/format.test.ts @@ -1,5 +1,36 @@ -import { describe, expect, it } from "vitest"; -import { stripThinkingTags } from "./format.ts"; +import { describe, expect, it, vi } from "vitest"; +import { formatAgo, stripThinkingTags } from "./format.ts"; + +describe("formatAgo", () => { + it("returns 'just now' for timestamps less than 60s in the future", () => { + expect(formatAgo(Date.now() + 30_000)).toBe("just now"); + }); + + it("returns 'Xm from now' for future timestamps", () => { + expect(formatAgo(Date.now() + 5 * 60_000)).toBe("5m from now"); + }); + + it("returns 'Xh from now' for future timestamps", () => { + expect(formatAgo(Date.now() + 3 * 60 * 60_000)).toBe("3h from now"); + }); + + it("returns 'Xd from now' for future timestamps beyond 48h", () => { + expect(formatAgo(Date.now() + 3 * 24 * 60 * 60_000)).toBe("3d from now"); + }); + + it("returns 'Xs ago' for recent past timestamps", () => { + expect(formatAgo(Date.now() - 10_000)).toBe("10s ago"); + }); + + it("returns 'Xm ago' for past timestamps", () => { + expect(formatAgo(Date.now() - 5 * 60_000)).toBe("5m ago"); + }); + + it("returns 'n/a' for null/undefined", () => { + expect(formatAgo(null)).toBe("n/a"); + expect(formatAgo(undefined)).toBe("n/a"); + }); +}); describe("stripThinkingTags", () => { it("strips segments", () => { diff --git a/ui/src/ui/format.ts b/ui/src/ui/format.ts index d1073b8f80..812aaa3fb1 100644 --- a/ui/src/ui/format.ts +++ b/ui/src/ui/format.ts @@ -12,23 +12,22 @@ export function formatAgo(ms?: number | null): string { return "n/a"; } const diff = Date.now() - ms; - if (diff < 0) { - return "just now"; - } - const sec = Math.round(diff / 1000); + const absDiff = Math.abs(diff); + const suffix = diff < 0 ? "from now" : "ago"; + const sec = Math.round(absDiff / 1000); if (sec < 60) { - return `${sec}s ago`; + return diff < 0 ? "just now" : `${sec}s ago`; } const min = Math.round(sec / 60); if (min < 60) { - return `${min}m ago`; + return `${min}m ${suffix}`; } const hr = Math.round(min / 60); if (hr < 48) { - return `${hr}h ago`; + return `${hr}h ${suffix}`; } const day = Math.round(hr / 24); - return `${day}d ago`; + return `${day}d ${suffix}`; } export function formatDurationMs(ms?: number | null): string {