fix(common): parse `YYYY-MM` strings as UTC dates (#40620)

In 2aba8b0 we fixed the DatePipe so that when it parsed date strings
that looked like `YYYY-MM-DD` it created a UTC date that was not
affected by the local timezone of the JavaScript engine.

This commit does the same for date strings of the form `YYYY-MM`
and `YYYY`.

Fixes #33944

PR Close #40620
This commit is contained in:
Pete Bacon Darwin 2021-01-28 20:49:07 +00:00 committed by Misko Hevery
parent 028b38352a
commit b6cd38ff05
2 changed files with 14 additions and 2 deletions

View File

@ -718,7 +718,7 @@ export function toDate(value: string|number|Date): Date {
return new Date(parsedNb); return new Date(parsedNb);
} }
if (/^(\d{4}-\d{1,2}-\d{1,2})$/.test(value)) { if (/^(\d{4}(-\d{1,2}(-\d{1,2})?)?)$/.test(value)) {
/* For ISO Strings without time the day, month and year must be extracted from the ISO String /* For ISO Strings without time the day, month and year must be extracted from the ISO String
before Date creation to avoid time offset and errors in the new Date. before Date creation to avoid time offset and errors in the new Date.
If we only replace '-' with ',' in the ISO String ("2015,01,01"), and try to create a new If we only replace '-' with ',' in the ISO String ("2015,01,01"), and try to create a new
@ -726,7 +726,7 @@ export function toDate(value: string|number|Date): Date {
If we leave the '-' ("2015-01-01") and try to create a new Date("2015-01-01") the timeoffset If we leave the '-' ("2015-01-01") and try to create a new Date("2015-01-01") the timeoffset
is applied. is applied.
Note: ISO months are 0 for January, 1 for February, ... */ Note: ISO months are 0 for January, 1 for February, ... */
const [y, m, d] = value.split('-').map((val: string) => +val); const [y, m = 1, d = 1] = value.split('-').map((val: string) => +val);
return new Date(y, m - 1, d); return new Date(y, m - 1, d);
} }

View File

@ -60,6 +60,8 @@ describe('Format date', () => {
describe('formatDate', () => { describe('formatDate', () => {
const isoStringWithoutTime = '2015-01-01'; const isoStringWithoutTime = '2015-01-01';
const isoStringWithoutTimeOrDate = '2015-01';
const isoStringWithoutTimeOrDateOrMonth = '2015-01';
const defaultFormat = 'mediumDate'; const defaultFormat = 'mediumDate';
let date: Date; let date: Date;
@ -231,6 +233,16 @@ describe('Format date', () => {
expectDateFormatAs(isoStringWithoutTime, pattern, isoStringWithoutTimeFixtures[pattern]); expectDateFormatAs(isoStringWithoutTime, pattern, isoStringWithoutTimeFixtures[pattern]);
}); });
Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => {
expectDateFormatAs(
isoStringWithoutTimeOrDate, pattern, isoStringWithoutTimeFixtures[pattern]);
});
Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => {
expectDateFormatAs(
isoStringWithoutTimeOrDateOrMonth, pattern, isoStringWithoutTimeFixtures[pattern]);
});
const nightTime = new Date(2015, 5, 15, 2, 3, 1, 550); const nightTime = new Date(2015, 5, 15, 2, 3, 1, 550);
Object.keys(midnightCrossingPeriods).forEach(pattern => { Object.keys(midnightCrossingPeriods).forEach(pattern => {
expectDateFormatAs(nightTime, pattern, midnightCrossingPeriods[pattern]); expectDateFormatAs(nightTime, pattern, midnightCrossingPeriods[pattern]);