Skip to content

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

Description

@maximilliangrand

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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions