#15875: fix(cron): normalize seconds to milliseconds in timestamps
stale
size: XS
Cluster:
Cron Enhancements and Fixes
## Problem
The cron system was treating numeric timestamps inconsistently (#15729).
Users passing seconds-based Unix timestamps (10 digits like `1771005600`) would see schedules off by 1000x because JavaScript Date expects milliseconds (13 digits like `1771005600000`).
## Root Cause
When users pass `at` or `atMs` as numeric seconds, the code directly used them as milliseconds:
- `new Date(1771005600)` produces year 1970 (wrong)
- `new Date(1771005600000)` produces year 2026 (correct)
## Solution
Add `normalizeTimestampToMs()` helper that detects seconds vs milliseconds:
- Values < 1,000,000,000,000 (10^12) are treated as seconds and multiplied by 1000
- Values >= 1,000,000,000,000 are treated as milliseconds and used as-is
Files changed:
- `src/cron/normalize.ts`: Add helper and use in `coerceSchedule()`
- `src/cron/service/store.ts`: Add inline helper in migration code
## Testing
Before fix:
- Input: `1771005600` (seconds) → Schedules to year 58090 (wrong)
After fix:
- Input: `1771005600` (seconds) → Correctly schedules to 2026-02-13 18:00:00 UTC
- Input: `1771005600000` (ms) → Still works correctly
Fixes #15729
<!-- greptile_comment -->
<h2>Greptile Overview</h2>
<h3>Greptile Summary</h3>
This change normalizes numeric cron schedule timestamps so seconds-based Unix timestamps are treated as seconds and converted to milliseconds (JS `Date` expects ms). It introduces a `normalizeTimestampToMs()` helper in `src/cron/normalize.ts` for request/input normalization, and applies the same seconds→ms conversion during cron store load/migration in `src/cron/service/store.ts` so persisted `at`/`atMs` values are corrected and stored as ISO strings.
No merge-blocking issues were found in the updated normalization or migration paths.
<h3>Confidence Score: 5/5</h3>
- This PR is safe to merge with minimal risk.
- The change is narrowly scoped to timestamp normalization, uses a clear seconds-vs-milliseconds threshold, and is applied consistently in both input normalization and store migration without altering unrelated scheduling logic.
- No files require special attention
<sub>Last reviewed commit: cf4398b</sub>
<!-- greptile_other_comments_section -->
<!-- /greptile_comment -->
Most Similar PRs
#15754: fix: handle Unix timestamps in seconds in parseAbsoluteTimeMs
by MisterGuy420 · 2026-02-13
86.1%
#15784: fix: timestamp parsing should convert seconds to milliseconds
by murasame-desu-ai · 2026-02-13
85.2%
#9670: fix: handle numeric string timestamps in cron schedule normalizatio...
by divol89 · 2026-02-05
82.6%
#8811: fix(cron): handle atMs fallback for kind=at jobs
by hlibr · 2026-02-04
81.5%
#12303: fix(cron): correct nextRunAtMs calculation and prevent timer stall
by colddonkey · 2026-02-09
78.0%
#13288: fix(cron): normalize string schedule/payload from non-frontier LLMs
by M00N7682 · 2026-02-10
77.8%
#5624: add support_human_readable_time_format in cron
by simran122 · 2026-01-31
77.4%
#9684: fix: cron race condition - run due jobs before recomputing nextRunA...
by divol89 · 2026-02-05
76.7%
#11813: fix(cron): ensure 'at' schedule type correctly registers nextWakeAt...
by leo-reifying · 2026-02-08
76.3%
#14667: fix: preserve missed cron runs when updating job schedule
by WalterSumbon · 2026-02-12
75.7%