fix(type): parse string.date.epoch.parse input as milliseconds - #1669
Merged
Merged
Conversation
The morph passed the validated integer string straight to new Date(), which treats it as a date string instead of a timestamp. "0" became 2000-01-01 in local time and "1700000000000" became an Invalid Date. Convert the string to a number first so it is read as a Unix timestamp in milliseconds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the complete diff at 0dcd3da was reviewed: a one-line fix to the string.date.epoch.parse morph plus a regression test.
string.date.epoch.parsenow reads its input as milliseconds —ark/type/keywords/string.ts:306changesnew Date(s)tonew Date(Number.parseInt(s)), so the already-validated integer string is interpreted as a Unix timestamp rather than handed toDate's string parser (which returned a wrong orInvaliddate for accepted input).- Regression test added —
ark/type/__tests__/keywords/date.test.ts:36pins"0", a millisecond timestamp, and a negative timestamp to exact ISO strings, and rejects"1.5".
I confirmed the fix is correct and the test is genuine, not theatre:
- The input is validated by
epochRoot(stringInteger.rootnarrowed throughnumber.epoch), so by the time the morph runs the string is a well-formed integer in the safe timestamp range[-8_640_000_000_000_000, 8_640_000_000_000_000]—Number.parseIntcannot truncate or overflow here, matching the identical parse already done in theepochRootnarrow atstring.ts:283. - Reverting only
string.tsto the base makes the new test fail ('2000-01-01T05:00:00.000Z'vs'1970-01-01T00:00:00.000Z'); restored, all fourkeywords/datetests pass.prettier --checkis clean on both changed files.
The behavior change is a bug fix (the keyword's documented contract is a Unix timestamp), so no doc update is needed; the release PR can carry the changelog note.
DeepSeek Flash (free via Pullfrog for OSS) | 𝕏
ssalbdivad
approved these changes
Oct 1, 2026
ssalbdivad
left a comment
Member
There was a problem hiding this comment.
Nice catch, thanks for the fix!
4 tasks done
ssalbdivad
added a commit
that referenced
this pull request
Oct 1, 2026
Bumps all publishable packages and documents the changes merged since 2.2.6: - fix `this[]` in self-referential object types (#1618, fixes #1406, @yharaskrik) - parse string.date.epoch.parse input as milliseconds (#1669, @breken-ai) - keep uppercase UUIDs valid in string.uuid JSON Schema (#1670, @breken-ai) - render nested bigints correctly in error messages (#1626, fixes #1477, @chatman-media) - release unused parse ids from the global registry (#1673, fixes #1584 for equivalent types, @isaacwasserman) - fix crashes on Hermes and Turbopack (#1674, fixes #1645 and #1643) #1590 only adds tests, so it has no changelog entry. Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

string.date.epoch.parsepasses the validated integer string straight tonew Date(). With a string argument,Dateruns its date-string parser instead of reading the value as a timestamp. So the keyword returns the wrong date, or an Invalid Date, for input it has just accepted:This means something like
type({ createdAt: "string.date.epoch.parse" })on a query string or CSV column accepts the value and then hands the caller a date that is wrong orNaN, with no error. The rootstring.date.epochvalidator is already correct: it parses the string as a number and checks it againstnumber.epoch. Only the morph skipped that step.Fix: convert the string with
Number.parseIntbefore building theDate(the input is already validated as a well-formed integer string in the safe epoch range). One line inark/type/keywords/string.ts.Test: added
string.date.epoch.parsetoark/type/__tests__/keywords/date.test.ts. It covers"0", a current millisecond timestamp, a negative timestamp and a non-integer rejection. The dates are compared as ISO strings, so the test doesn't depend on the host timezone.'2000-01-01T05:00:00.000Z'vs'1970-01-01T00:00:00.000Z')date.test.tsChecklist:
mainbranch (based on 42c17df)pnpm prCheckslocally: I ran part of it.pnpm testpasses (1752 passing),tscis clean, and prettier and eslint--max-warnings=0pass on the changed files. I did not run the benches,buildRepoortestTsVersions.I used an AI coding assistant to find and fix this, and I checked the change and the before/after test results myself.