Skip to content

Commit

Permalink
Return Invalid DateTime for using meridiem with 24-hour (#1549)
Browse files Browse the repository at this point in the history
  • Loading branch information
Matthematic authored and Matthew Carr committed Jan 6, 2024
1 parent 3125686 commit 7152ca4
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 5 deletions.
8 changes: 6 additions & 2 deletions src/datetime.js
Original file line number Diff line number Diff line change
Expand Up @@ -901,9 +901,13 @@ export default class DateTime {
numberingSystem,
defaultToEN: true,
}),
[vals, parsedZone, specificOffset, invalid] = parseFromTokens(localeToUse, text, fmt);
[vals, parsedZone, specificOffset, invalid, explanation] = parseFromTokens(
localeToUse,
text,
fmt
);
if (invalid) {
return DateTime.invalid(invalid);
return DateTime.invalid(invalid, explanation);
} else {
return parseDataToDateTime(vals, parsedZone, opts, `format ${fmt}`, text, specificOffset);
}
Expand Down
20 changes: 18 additions & 2 deletions src/impl/tokenParser.js
Original file line number Diff line number Diff line change
Expand Up @@ -450,14 +450,30 @@ export function explainFromTokens(locale, input, format) {
throw new ConflictingSpecificationError(
"Can't include meridiem when specifying 24-hour format"
);
} else if (
hasOwnProperty(matches, "h") &&
matches["h"] > 12 &&
tokens.find((t) => t.val === "h" || t.val === "hh")
) {
const hourValue = matches["h"];
return {
input,
tokens,
invalidReason: "unit out of range",
invalidExplanation: `you specified ${hourValue} (of type ${typeof hourValue}) as an hour along with a meridiem, which is invalid`,
};
}
return { input, tokens, regex, rawMatches, matches, result, zone, specificOffset };
}
}

export function parseFromTokens(locale, input, format) {
const { result, zone, specificOffset, invalidReason } = explainFromTokens(locale, input, format);
return [result, zone, specificOffset, invalidReason];
const { result, zone, specificOffset, invalidReason, invalidExplanation } = explainFromTokens(
locale,
input,
format
);
return [result, zone, specificOffset, invalidReason, invalidExplanation];
}

export function formatOptsToTokens(formatOpts, locale) {
Expand Down
32 changes: 31 additions & 1 deletion test/datetime/tokenParse.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,40 @@ test("DateTime.fromFormat() parses basic times", () => {
expect(i.millisecond).toBe(445);
});

test("DateTime.fromFormat() yields Invalid reason for invalid 12-hour time", () => {
const i = DateTime.fromFormat("11-08-2023 15:00 AM", "MM-dd-yyyy h:mm a");
expect(i.invalid).not.toBeNull();
expect(i.invalid.reason).toEqual("unit out of range");
expect(i.invalid.explanation).toEqual(
"you specified 15 (of type number) as an hour along with a meridiem, which is invalid"
);
});

test("DateTime.fromFormat() yields Invalid reason for invalid 12-hour time with padding", () => {
const i = DateTime.fromFormat("11-08-2023 15:00 AM", "MM-dd-yyyy hh:mm a");
expect(i.invalid).not.toBeNull();
expect(i.invalid.reason).toEqual("unit out of range");
expect(i.invalid.explanation).toEqual(
"you specified 15 (of type number) as an hour along with a meridiem, which is invalid"
);
});

test("DateTime.fromFormat() throws ConflictingSpecificationError for invalid format", () => {
expect(() => {
DateTime.fromFormat("11-08-2023 12:00 AM", "MM-dd-yyyy H:mm a");
}).toThrowError(
ConflictingSpecificationError,
"Can't include meridiem when specifying 24-hour format"
);
});

test("DateTime.fromFormat() yields Invalid reason 'unparseable' for incompatible formats", () => {
const i = DateTime.fromFormat("Mar 3, 2020", "MMM dd, yyyy");
expect(i.invalid).not.toBeNull;
expect(i.invalid).not.toBeNull();
expect(i.invalid.reason).toEqual("unparsable");
expect(i.invalid.explanation).toEqual(
'the input "Mar 3, 2020" can\'t be parsed as format MMM dd, yyyy'
);
});

test("DateTime.fromFormat() parses with variable-length input", () => {
Expand Down

0 comments on commit 7152ca4

Please sign in to comment.