Skip to content

Commit 093cc04

Browse files
Dzmitry Shylovichmhevery
authored andcommitted
fix(common): DatePipe parses input string if it's not a valid date in browser (#13895)
Closes #12334 Closes #13874 PR Close #13895
1 parent 9d2c712 commit 093cc04

File tree

2 files changed

+41
-6
lines changed

2 files changed

+41
-6
lines changed

modules/@angular/common/src/pipes/date_pipe.ts

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,13 @@
77
*/
88

99
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
10-
1110
import {NumberWrapper} from '../facade/lang';
12-
1311
import {DateFormatter} from './intl';
1412
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
1513

16-
14+
const ISO8601_DATE_REGEX =
15+
/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
16+
// 1 2 3 4 5 6 7 8 9 10 11
1717

1818
/**
1919
* @ngModule CommonModule
@@ -130,7 +130,12 @@ export class DatePipe implements PipeTransform {
130130
}
131131

132132
if (!isDate(date)) {
133-
throw new InvalidPipeArgumentError(DatePipe, value);
133+
let match: RegExpMatchArray;
134+
if ((typeof value === 'string') && (match = value.match(ISO8601_DATE_REGEX))) {
135+
date = isoStringToDate(match);
136+
} else {
137+
throw new InvalidPipeArgumentError(DatePipe, value);
138+
}
134139
}
135140

136141
return DateFormatter.format(date, this._locale, DatePipe._ALIASES[pattern] || pattern);
@@ -144,3 +149,27 @@ function isBlank(obj: any): boolean {
144149
function isDate(obj: any): obj is Date {
145150
return obj instanceof Date && !isNaN(obj.valueOf());
146151
}
152+
153+
function isoStringToDate(match: RegExpMatchArray): Date {
154+
const date = new Date(0);
155+
let tzHour = 0;
156+
let tzMin = 0;
157+
const dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear;
158+
const timeSetter = match[8] ? date.setUTCHours : date.setHours;
159+
160+
if (match[9]) {
161+
tzHour = toInt(match[9] + match[10]);
162+
tzMin = toInt(match[9] + match[11]);
163+
}
164+
dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
165+
const h = toInt(match[4] || '0') - tzHour;
166+
const m = toInt(match[5] || '0') - tzMin;
167+
const s = toInt(match[6] || '0');
168+
const ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
169+
timeSetter.call(date, h, m, s, ms);
170+
return date;
171+
}
172+
173+
function toInt(str: string): number {
174+
return parseInt(str, 10);
175+
}

modules/@angular/common/test/pipes/date_pipe_spec.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ export function main() {
5959
() => { expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); });
6060

6161
it('should not support other objects',
62-
() => { expect(() => pipe.transform({})).toThrowError(); });
62+
() => expect(() => pipe.transform({})).toThrowError(/Invalid argument/));
6363
});
6464

6565
describe('transform', () => {
@@ -190,8 +190,14 @@ export function main() {
190190

191191
});
192192

193+
it('should format invalid in IE ISO date',
194+
() => expect(pipe.transform('2017-01-11T09:25:14.014-0500')).toEqual('Jan 11, 2017'));
195+
196+
it('should format invalid in Safari ISO date',
197+
() => expect(pipe.transform('2017-01-20T19:00:00+0000')).toEqual('Jan 20, 2017'));
198+
193199
it('should remove bidi control characters',
194-
() => { expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10); });
200+
() => expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10));
195201
});
196202
});
197203
}

0 commit comments

Comments
 (0)