mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
feat(common): throw error for suspicious date patterns (#59798)
Adjusts the date pipe and formatDate function to detect suspicious usages of the week-numbering year formatter without including the week number, as this is often confused for the calendar year and likely to result in incorrect results near New Years, meaning that those issues aren't typically caught during development. This commit starts throwing a development-only error to reveal this issue right away. BREAKING CHANGE: Using the `Y` formatter (week-numbering year) without also including `w` (week number) is now detected as suspicious date pattern, as `y` is typically intended. PR Close #59798
This commit is contained in:
@@ -21,6 +21,9 @@ export const enum RuntimeErrorCode {
|
||||
// NgForOf errors
|
||||
NG_FOR_MISSING_DIFFER = -2200,
|
||||
|
||||
// I18n errors
|
||||
SUSPICIOUS_DATE_FORMAT = 2300,
|
||||
|
||||
// Keep 2800 - 2900 for Http Errors.
|
||||
|
||||
// Image directive errors
|
||||
|
||||
@@ -6,6 +6,11 @@
|
||||
* found in the LICENSE file at https://angular.dev/license
|
||||
*/
|
||||
|
||||
import {
|
||||
ɵRuntimeError as RuntimeError,
|
||||
ɵformatRuntimeError as formatRuntimeError,
|
||||
} from '@angular/core';
|
||||
|
||||
import {
|
||||
FormatWidth,
|
||||
FormStyle,
|
||||
@@ -24,6 +29,7 @@ import {
|
||||
Time,
|
||||
TranslationWidth,
|
||||
} from './locale_data_api';
|
||||
import {RuntimeErrorCode} from '../errors';
|
||||
|
||||
export const ISO8601_DATE_REGEX =
|
||||
/^(\d{4,})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
|
||||
@@ -104,6 +110,10 @@ export function formatDate(
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof ngDevMode === 'undefined' || ngDevMode) {
|
||||
assertValidDateFormat(parts);
|
||||
}
|
||||
|
||||
let dateTimezoneOffset = date.getTimezoneOffset();
|
||||
if (timezone) {
|
||||
dateTimezoneOffset = timezoneToOffset(timezone, dateTimezoneOffset);
|
||||
@@ -123,6 +133,29 @@ export function formatDate(
|
||||
return text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that the given date format is free from common mistakes. Throws an
|
||||
* error if one is found (except for the case of all "Y", in which case we just
|
||||
* log a warning). This should only be called in development mode.
|
||||
*/
|
||||
function assertValidDateFormat(parts: string[]) {
|
||||
if (parts.some((part) => /^Y+$/.test(part)) && !parts.some((part) => /^w+$/.test(part))) {
|
||||
// "Y" indicates "week-based year", which differs from the actual calendar
|
||||
// year for a few days around Jan 1 most years. Unless "w" is also
|
||||
// present (e.g. a date like "2024-W52") this is likely a mistake. Users
|
||||
// probably meant "y" instead.
|
||||
const message = `Suspicious use of week-based year "Y" in date pattern "${parts.join(
|
||||
'',
|
||||
)}". Did you mean to use calendar year "y" instead?`;
|
||||
if (parts.length === 1) {
|
||||
// NOTE: allow "YYYY" with just a warning, since it's used in tests.
|
||||
console.error(formatRuntimeError(RuntimeErrorCode.SUSPICIOUS_DATE_FORMAT, message));
|
||||
} else {
|
||||
throw new RuntimeError(RuntimeErrorCode.SUSPICIOUS_DATE_FORMAT, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Date object with the given date value, and the time set to midnight.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user