fix(common): DatePipe parses input string if it's not a valid date in browser (#13895)

Closes #12334
Closes #13874

PR Close #13895
This commit is contained in:
Dzmitry Shylovich 2017-01-30 21:44:19 +03:00 committed by Miško Hevery
parent 9d2c71269b
commit 093cc04748
2 changed files with 41 additions and 6 deletions

View File

@ -7,13 +7,13 @@
*/ */
import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core'; import {Inject, LOCALE_ID, Pipe, PipeTransform} from '@angular/core';
import {NumberWrapper} from '../facade/lang'; import {NumberWrapper} from '../facade/lang';
import {DateFormatter} from './intl'; import {DateFormatter} from './intl';
import {InvalidPipeArgumentError} from './invalid_pipe_argument_error'; import {InvalidPipeArgumentError} from './invalid_pipe_argument_error';
const ISO8601_DATE_REGEX =
/^(\d{4})-?(\d\d)-?(\d\d)(?:T(\d\d)(?::?(\d\d)(?::?(\d\d)(?:\.(\d+))?)?)?(Z|([+-])(\d\d):?(\d\d))?)?$/;
// 1 2 3 4 5 6 7 8 9 10 11
/** /**
* @ngModule CommonModule * @ngModule CommonModule
@ -130,7 +130,12 @@ export class DatePipe implements PipeTransform {
} }
if (!isDate(date)) { if (!isDate(date)) {
throw new InvalidPipeArgumentError(DatePipe, value); let match: RegExpMatchArray;
if ((typeof value === 'string') && (match = value.match(ISO8601_DATE_REGEX))) {
date = isoStringToDate(match);
} else {
throw new InvalidPipeArgumentError(DatePipe, value);
}
} }
return DateFormatter.format(date, this._locale, DatePipe._ALIASES[pattern] || pattern); return DateFormatter.format(date, this._locale, DatePipe._ALIASES[pattern] || pattern);
@ -144,3 +149,27 @@ function isBlank(obj: any): boolean {
function isDate(obj: any): obj is Date { function isDate(obj: any): obj is Date {
return obj instanceof Date && !isNaN(obj.valueOf()); return obj instanceof Date && !isNaN(obj.valueOf());
} }
function isoStringToDate(match: RegExpMatchArray): Date {
const date = new Date(0);
let tzHour = 0;
let tzMin = 0;
const dateSetter = match[8] ? date.setUTCFullYear : date.setFullYear;
const timeSetter = match[8] ? date.setUTCHours : date.setHours;
if (match[9]) {
tzHour = toInt(match[9] + match[10]);
tzMin = toInt(match[9] + match[11]);
}
dateSetter.call(date, toInt(match[1]), toInt(match[2]) - 1, toInt(match[3]));
const h = toInt(match[4] || '0') - tzHour;
const m = toInt(match[5] || '0') - tzMin;
const s = toInt(match[6] || '0');
const ms = Math.round(parseFloat('0.' + (match[7] || 0)) * 1000);
timeSetter.call(date, h, m, s, ms);
return date;
}
function toInt(str: string): number {
return parseInt(str, 10);
}

View File

@ -59,7 +59,7 @@ export function main() {
() => { expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); }); () => { expect(() => pipe.transform(isoStringWithoutTime)).not.toThrow(); });
it('should not support other objects', it('should not support other objects',
() => { expect(() => pipe.transform({})).toThrowError(); }); () => expect(() => pipe.transform({})).toThrowError(/Invalid argument/));
}); });
describe('transform', () => { describe('transform', () => {
@ -190,8 +190,14 @@ export function main() {
}); });
it('should format invalid in IE ISO date',
() => expect(pipe.transform('2017-01-11T09:25:14.014-0500')).toEqual('Jan 11, 2017'));
it('should format invalid in Safari ISO date',
() => expect(pipe.transform('2017-01-20T19:00:00+0000')).toEqual('Jan 20, 2017'));
it('should remove bidi control characters', it('should remove bidi control characters',
() => { expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10); }); () => expect(pipe.transform(date, 'MM/dd/yyyy').length).toEqual(10));
}); });
}); });
} }