date() cast mis-parses sub-3-digit fractional seconds (.5Z -> 5ms instead of 500ms)
Describe the bug
date().cast() mis-parses ISO datetimes whose fractional-seconds part has fewer than 3 digits. .5 (= 500 ms) is read as 5 ms, .05 as 5 ms instead of 50, .12 as 12 instead of 120. Only exactly-3-digit fractions (.123) are correct. The result is silently wrong by up to 495 ms.
To Reproduce
import { date } from 'yup';
date().cast('2020-01-01T00:00:00.5Z').toISOString();
// actual: "2020-01-01T00:00:00.005Z"
// expected: "2020-01-01T00:00:00.500Z" (same as new Date('2020-01-01T00:00:00.5Z'))Sweep on yup 1.7.1 vs native Date:
| input | yup ms | Date ms |
|---|---|---|
.1Z |
1 | 100 |
.05Z |
5 | 50 |
.12Z |
12 | 120 |
.5Z |
5 | 500 |
.123Z |
123 | 123 (ok) |
date().validate('2020-01-01T00:00:00.5Z') likewise resolves to 2020-01-01T00:00:00.005Z.
Expected behavior
Fractional seconds match the native ISO 8601 parser (new Date / Date.parse), which yup's parseIsoDate.ts header says it enhances: .5 -> 500 ms.
Cause
In src/util/parseIsoDate.ts, the milliseconds field is toNumber(regexResult[7].substring(0, 3)) -- it truncates to 3 fractional digits but never right-pads, so a fraction shorter than 3 digits is parsed as a literal integer. Fix: .substring(0, 3).padEnd(3, '0').
(Distinct from the merged #60, which fixed the 3-digit leading-zero case .012->.120; that case is now correct, but sub-3-digit fractions remain wrong.)
Platform
- yup 1.7.1
- Node 20
Source: jquense/yup