fix(cli): keep render filename timestamp local (#2470)

* fix(cli): keep render filename date and time local

* fix(render): share local output timestamps
This commit is contained in:
Miguel Ángel
2026-07-15 08:13:13 -04:00
committed by GitHub
parent 10b3351974
commit 017183ad66
5 changed files with 33 additions and 10 deletions
+4 -5
View File
@@ -76,6 +76,7 @@ import { VERSION } from "../version.js";
import { isDevMode } from "../utils/env.js";
import { buildDockerRunArgs, resolveDockerPlatform } from "../utils/dockerRunArgs.js";
import { normalizeErrorMessage } from "../utils/errorMessage.js";
import { formatRenderOutputTimestamp } from "@hyperframes/core";
import { runEnvironmentChecks } from "../browser/preflight.js";
import { detectH264EncoderMode } from "../browser/ffmpeg.js";
import { chromeLaunchRemediation } from "../browser/linuxDeps.js";
@@ -610,16 +611,14 @@ export default defineCommand({
// ── Resolve output path ───────────────────────────────────────────────
const rendersDir = resolve("renders");
const ext = FORMAT_EXT[format] ?? ".mp4";
// fallow-ignore-next-line code-duplication
const now = new Date();
const datePart = now.toISOString().slice(0, 10);
const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
const timestamp = formatRenderOutputTimestamp(now);
const batchOutputTemplate = args.output
? args.output
: join(rendersDir, `${project.name}_${datePart}_${timePart}_{index}${ext}`);
: join(rendersDir, `${project.name}_${timestamp}_{index}${ext}`);
const outputPath = args.output
? resolve(args.output)
: join(rendersDir, `${project.name}_${datePart}_${timePart}${ext}`);
: join(rendersDir, `${project.name}_${timestamp}${ext}`);
// Ensure output directory exists
if (!batchPath) mkdirSync(dirname(outputPath), { recursive: true });
+1
View File
@@ -231,6 +231,7 @@ export { createGSAPFrameAdapter } from "./adapters/gsap";
// Text measurement
export { fitTextFontSize } from "./text/index.js";
export type { FitTextOptions, FitTextResult } from "./text/index.js";
export { formatRenderOutputTimestamp } from "./utils/renderOutputTimestamp.js";
// Runtime helpers (composition-side)
export { getVariables } from "./runtime/getVariables.js";
@@ -0,0 +1,19 @@
import { describe, expect, it } from "vitest";
import { formatRenderOutputTimestamp } from "./renderOutputTimestamp.js";
describe("formatRenderOutputTimestamp", () => {
it.each([
["late local evening", "2026-07-14T22:55:06-07:00", "2026-07-14_22-55-06"],
["single-digit calendar and clock fields", "2026-01-05T04:07:03-08:00", "2026-01-05_04-07-03"],
])("uses one padded local calendar for %s", (_name, input, expected) => {
const previousTimezone = process.env.TZ;
process.env.TZ = "America/Los_Angeles";
try {
expect(formatRenderOutputTimestamp(new Date(input))).toBe(expected);
} finally {
if (previousTimezone === undefined) delete process.env.TZ;
else process.env.TZ = previousTimezone;
}
});
});
@@ -0,0 +1,7 @@
/** Format a render/job timestamp from one local calendar and clock. */
export function formatRenderOutputTimestamp(now: Date): string {
const pad = (value: number): string => String(value).padStart(2, "0");
const datePart = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
const timePart = `${pad(now.getHours())}-${pad(now.getMinutes())}-${pad(now.getSeconds())}`;
return `${datePart}_${timePart}`;
}
+2 -5
View File
@@ -4,7 +4,7 @@ import { existsSync, readFileSync, mkdirSync, unlinkSync, readdirSync, statSync
import { join } from "node:path";
import type { StudioApiAdapter, RenderJobState } from "../types.js";
import { VALID_CANVAS_RESOLUTIONS, type CanvasResolution } from "@hyperframes/parsers";
import { parseFps } from "@hyperframes/core";
import { formatRenderOutputTimestamp, parseFps } from "@hyperframes/core";
import { resolveWithinProject } from "../helpers/safePath.js";
import { isVariablesPayload, VARIABLES_PAYLOAD_ERROR } from "../helpers/variablesPayload.js";
@@ -107,11 +107,8 @@ export function registerRenderRoutes(api: Hono, adapter: StudioApiAdapter): void
variables = body.variables;
}
// fallow-ignore-next-line code-duplication
const now = new Date();
const datePart = now.toISOString().slice(0, 10);
const timePart = now.toTimeString().slice(0, 8).replace(/:/g, "-");
const jobId = `${project.id}_${datePart}_${timePart}`;
const jobId = `${project.id}_${formatRenderOutputTimestamp(now)}`;
const rendersDir = adapter.rendersDir(project);
if (!existsSync(rendersDir)) mkdirSync(rendersDir, { recursive: true });
const ext = FORMAT_EXT[format] ?? ".mp4";