#2339·yup

date() cast mis-parses sub-3-digit fractional seconds (.5Z -> 5ms instead of 500ms)

Author: maximilliangrandCreated Aug 15, 2026Updated Aug 15, 2026

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

javascript
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