fix(auto-reply): guard date stamp formatting

This commit is contained in:
Peter Steinberger
2026-05-30 07:58:12 -04:00
parent 07e0af44b3
commit fb61363763
4 changed files with 35 additions and 36 deletions

View File

@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest";
import { normalizeTimestamp } from "./date-time.js";
import { afterEach, describe, expect, it, vi } from "vitest";
import { formatDateStamp, normalizeTimestamp } from "./date-time.js";
describe("normalizeTimestamp", () => {
it("normalizes numeric second and millisecond timestamps", () => {
@@ -18,3 +18,15 @@ describe("normalizeTimestamp", () => {
expect(normalizeTimestamp("999999999999999999999999")).toBeUndefined();
});
});
describe("formatDateStamp", () => {
afterEach(() => {
vi.restoreAllMocks();
});
it("falls back when nowMs is outside Date range", () => {
vi.spyOn(Date, "now").mockReturnValue(Date.UTC(2026, 4, 30, 12, 0, 0));
expect(formatDateStamp(8_640_000_000_000_001, "UTC")).toBe("2026-05-30");
});
});

View File

@@ -1,4 +1,5 @@
import { execFileSync } from "node:child_process";
import { asDateTimestampMs } from "../shared/number-coercion.js";
export type TimeFormatPreference = "auto" | "12" | "24";
export type ResolvedTimeFormat = "12" | "24";
@@ -40,6 +41,24 @@ export function resolveUserTimeFormat(preference?: TimeFormatPreference): Resolv
return cachedTimeFormat;
}
export function formatDateStamp(nowMs: number, timeZone: string): string {
const timestampMs = asDateTimestampMs(nowMs) ?? Date.now();
const date = new Date(timestampMs);
const parts = new Intl.DateTimeFormat("en-US", {
timeZone,
year: "numeric",
month: "2-digit",
day: "2-digit",
}).formatToParts(date);
const year = parts.find((part) => part.type === "year")?.value;
const month = parts.find((part) => part.type === "month")?.value;
const day = parts.find((part) => part.type === "day")?.value;
if (year && month && day) {
return `${year}-${month}-${day}`;
}
return date.toISOString().slice(0, 10);
}
export function normalizeTimestamp(
raw: unknown,
): { timestampMs: number; timestampUtc: string } | undefined {

View File

@@ -2,7 +2,7 @@ import fs from "node:fs";
import path from "node:path";
import { resolveAgentContextLimits } from "../../agents/agent-scope.js";
import { resolveCronStyleNow } from "../../agents/current-time.js";
import { resolveUserTimezone } from "../../agents/date-time.js";
import { formatDateStamp, resolveUserTimezone } from "../../agents/date-time.js";
import type { OpenClawConfig } from "../../config/types.openclaw.js";
import { openRootFile } from "../../infra/boundary-file-read.js";
import { normalizeLowercaseStringOrEmpty } from "../../shared/string-coerce.js";
@@ -40,22 +40,6 @@ function matchesSectionSet(sectionNames: string[], expectedSections: string[]):
return counts.size === 0;
}
function formatDateStamp(nowMs: number, timezone: string): string {
const parts = new Intl.DateTimeFormat("en-US", {
timeZone: timezone,
year: "numeric",
month: "2-digit",
day: "2-digit",
}).formatToParts(new Date(nowMs));
const year = parts.find((p) => p.type === "year")?.value;
const month = parts.find((p) => p.type === "month")?.value;
const day = parts.find((p) => p.type === "day")?.value;
if (year && month && day) {
return `${year}-${month}-${day}`;
}
return new Date(nowMs).toISOString().slice(0, 10);
}
/**
* Read critical sections from workspace AGENTS.md for post-compaction injection.
* Returns formatted system event text, or null if no AGENTS.md or no relevant sections.

View File

@@ -1,6 +1,6 @@
import fs from "node:fs";
import path from "node:path";
import { resolveUserTimezone } from "../../agents/date-time.js";
import { formatDateStamp, resolveUserTimezone } from "../../agents/date-time.js";
import type { OpenClawConfig } from "../../config/config.js";
import { openRootFile } from "../../infra/boundary-file-read.js";
import { uniqueStrings } from "../../shared/string-normalization.js";
@@ -64,22 +64,6 @@ function resolveStartupContextLimits(cfg?: OpenClawConfig) {
};
}
function formatDateStamp(nowMs: number, timezone: string): string {
const parts = new Intl.DateTimeFormat("en-US", {
timeZone: timezone,
year: "numeric",
month: "2-digit",
day: "2-digit",
}).formatToParts(new Date(nowMs));
const year = parts.find((part) => part.type === "year")?.value;
const month = parts.find((part) => part.type === "month")?.value;
const day = parts.find((part) => part.type === "day")?.value;
if (year && month && day) {
return `${year}-${month}-${day}`;
}
return new Date(nowMs).toISOString().slice(0, 10);
}
function shiftDateStampByCalendarDays(stamp: string, offsetDays: number): string {
const [yearRaw, monthRaw, dayRaw] = stamp.split("-").map((part) => Number.parseInt(part, 10));
if (!yearRaw || !monthRaw || !dayRaw) {