@@ -58,6 +58,9 @@ function range<T>(length: number, valueFunction: (index: number) => T): T[] {
5858/** Adapts the native JS Date for use with cdk-based components that work with dates. */
5959@Injectable ( )
6060export class NativeDateAdapter extends DateAdapter < Date > {
61+ /** Whether to clamp the date between 1 and 9999 to avoid IE and Edge errors. */
62+ private readonly _clampDate : boolean ;
63+
6164 /**
6265 * Whether to use `timeZone: 'utc'` with `Intl.DateTimeFormat` when formatting dates.
6366 * Without this `Intl.DateTimeFormat` sometimes chooses the wrong timeZone, which can throw off
@@ -71,10 +74,13 @@ export class NativeDateAdapter extends DateAdapter<Date> {
7174 super . setLocale ( matDateLocale ) ;
7275
7376 // IE does its own time zone correction, so we disable this on IE.
74- // TODO(mmalerba): replace with !platform.TRIDENT, logic currently duplicated to avoid breaking
75- // change from injecting the Platform.
76- this . useUtcForDisplay = ! ( typeof document === 'object' && ! ! document &&
77- / ( m s i e | t r i d e n t ) / i. test ( navigator . userAgent ) ) ;
77+ // TODO(mmalerba): replace with checks from PLATFORM, logic currently duplicated to avoid
78+ // breaking change from injecting the Platform.
79+ const isBrowser = typeof document === 'object' && ! ! document ;
80+ const isIE = isBrowser && / ( m s i e | t r i d e n t ) / i. test ( navigator . userAgent ) ;
81+
82+ this . useUtcForDisplay = ! isIE ;
83+ this . _clampDate = isIE || ( isBrowser && / ( e d g e ) / i. test ( navigator . userAgent ) ) ;
7884 }
7985
8086 getYear ( date : Date ) : number {
@@ -179,14 +185,23 @@ export class NativeDateAdapter extends DateAdapter<Date> {
179185 if ( ! this . isValid ( date ) ) {
180186 throw Error ( 'NativeDateAdapter: Cannot format invalid date.' ) ;
181187 }
188+
182189 if ( SUPPORTS_INTL_API ) {
190+ // On IE and Edge the i18n API will throw a hard error that can crash the entire app
191+ // if we attempt to format a date whose year is less than 1 or greater than 9999.
192+ if ( this . _clampDate && ( date . getFullYear ( ) < 1 || date . getFullYear ( ) > 9999 ) ) {
193+ date = this . clone ( date ) ;
194+ date . setFullYear ( Math . max ( 1 , Math . min ( 9999 , date . getFullYear ( ) ) ) ) ;
195+ }
196+
183197 if ( this . useUtcForDisplay ) {
184198 date = new Date ( Date . UTC (
185199 date . getFullYear ( ) , date . getMonth ( ) , date . getDate ( ) , date . getHours ( ) ,
186200 date . getMinutes ( ) , date . getSeconds ( ) , date . getMilliseconds ( ) ) ) ;
187201 displayFormat = { ...displayFormat , timeZone : 'utc' } ;
188202 }
189- let dtf = new Intl . DateTimeFormat ( this . locale , displayFormat ) ;
203+
204+ const dtf = new Intl . DateTimeFormat ( this . locale , displayFormat ) ;
190205 return this . _stripDirectionalityCharacters ( dtf . format ( date ) ) ;
191206 }
192207 return this . _stripDirectionalityCharacters ( date . toDateString ( ) ) ;
0 commit comments