@@ -67,6 +67,11 @@ export class NativeDateAdapter extends DateAdapter<Date> {
6767   * Without this `Intl.DateTimeFormat` sometimes chooses the wrong timeZone, which can throw off 
6868   * the result. (e.g. in the en-US locale `new Date(1800, 7, 14).toLocaleDateString()` 
6969   * will produce `'8/13/1800'`. 
70+    * 
71+    * TODO(mmalerba): drop this variable. It's not being used in the code right now. We're now 
72+    * getting the string representation of a Date object from it's utc representation. We're keeping 
73+    * it here for sometime, just for precaution, in case we decide to revert some of these changes 
74+    * though. 
7075   */ 
7176  useUtcForDisplay : boolean  =  true ; 
7277
@@ -97,34 +102,35 @@ export class NativeDateAdapter extends DateAdapter<Date> {
97102
98103  getMonthNames ( style : 'long'  |  'short'  |  'narrow' ) : string [ ]  { 
99104    if  ( SUPPORTS_INTL_API )  { 
100-       let  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { month : style } ) ; 
101-       return  range ( 12 ,  i  =>  this . _stripDirectionalityCharacters ( dtf . format ( new  Date ( 2017 ,  i ,  1 ) ) ) ) ; 
105+       const  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { month : style ,  timeZone : 'utc' } ) ; 
106+       return  range ( 12 ,  i  => 
107+           this . _stripDirectionalityCharacters ( this . _format ( dtf ,  new  Date ( 2017 ,  i ,  1 ) ) ) ) ; 
102108    } 
103109    return  DEFAULT_MONTH_NAMES [ style ] ; 
104110  } 
105111
106112  getDateNames ( ) : string [ ]  { 
107113    if  ( SUPPORTS_INTL_API )  { 
108-       let  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { day : 'numeric' } ) ; 
114+       const  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { day : 'numeric'  ,   timeZone :  'utc '} ) ; 
109115      return  range ( 31 ,  i  =>  this . _stripDirectionalityCharacters ( 
110-           dtf . format ( new  Date ( 2017 ,  0 ,  i  +  1 ) ) ) ) ; 
116+           this . _format ( dtf ,   new  Date ( 2017 ,  0 ,  i  +  1 ) ) ) ) ; 
111117    } 
112118    return  DEFAULT_DATE_NAMES ; 
113119  } 
114120
115121  getDayOfWeekNames ( style : 'long'  |  'short'  |  'narrow' ) : string [ ]  { 
116122    if  ( SUPPORTS_INTL_API )  { 
117-       let  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { weekday : style } ) ; 
123+       const  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { weekday : style ,   timeZone :  'utc' } ) ; 
118124      return  range ( 7 ,  i  =>  this . _stripDirectionalityCharacters ( 
119-           dtf . format ( new  Date ( 2017 ,  0 ,  i  +  1 ) ) ) ) ; 
125+           this . _format ( dtf ,   new  Date ( 2017 ,  0 ,  i  +  1 ) ) ) ) ; 
120126    } 
121127    return  DEFAULT_DAY_OF_WEEK_NAMES [ style ] ; 
122128  } 
123129
124130  getYearName ( date : Date ) : string  { 
125131    if  ( SUPPORTS_INTL_API )  { 
126-       let  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { year : 'numeric' } ) ; 
127-       return  this . _stripDirectionalityCharacters ( dtf . format ( date ) ) ; 
132+       const  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  { year : 'numeric'  ,   timeZone :  'utc '} ) ; 
133+       return  this . _stripDirectionalityCharacters ( this . _format ( dtf ,   date ) ) ; 
128134    } 
129135    return  String ( this . getYear ( date ) ) ; 
130136  } 
@@ -155,7 +161,6 @@ export class NativeDateAdapter extends DateAdapter<Date> {
155161    } 
156162
157163    let  result  =  this . _createDateWithOverflow ( year ,  month ,  date ) ; 
158- 
159164    // Check that the date wasn't above the upper bound for the month, causing the month to overflow 
160165    if  ( result . getMonth ( )  !=  month )  { 
161166      throw  Error ( `Invalid date "${ date }  " for month with index "${ month }  ".` ) ; 
@@ -190,15 +195,10 @@ export class NativeDateAdapter extends DateAdapter<Date> {
190195        date . setFullYear ( Math . max ( 1 ,  Math . min ( 9999 ,  date . getFullYear ( ) ) ) ) ; 
191196      } 
192197
193-       if  ( this . useUtcForDisplay )  { 
194-         date  =  new  Date ( Date . UTC ( 
195-             date . getFullYear ( ) ,  date . getMonth ( ) ,  date . getDate ( ) ,  date . getHours ( ) , 
196-             date . getMinutes ( ) ,  date . getSeconds ( ) ,  date . getMilliseconds ( ) ) ) ; 
197-         displayFormat  =  { ...displayFormat ,  timeZone : 'utc' } ; 
198-       } 
198+       displayFormat  =  { ...displayFormat ,  timeZone : 'utc' } ; 
199199
200200      const  dtf  =  new  Intl . DateTimeFormat ( this . locale ,  displayFormat ) ; 
201-       return  this . _stripDirectionalityCharacters ( dtf . format ( date ) ) ; 
201+       return  this . _stripDirectionalityCharacters ( this . _format ( dtf ,   date ) ) ; 
202202    } 
203203    return  this . _stripDirectionalityCharacters ( date . toDateString ( ) ) ; 
204204  } 
@@ -271,7 +271,7 @@ export class NativeDateAdapter extends DateAdapter<Date> {
271271
272272  /** Creates a date but allows the month and date to overflow. */ 
273273  private  _createDateWithOverflow ( year : number ,  month : number ,  date : number )  { 
274-     let  result  =  new  Date ( year ,  month ,  date ) ; 
274+     const  result  =  new  Date ( year ,  month ,  date ) ; 
275275
276276    // We need to correct for the fact that JS native Date treats years in range [0, 99] as 
277277    // abbreviations for 19xx. 
@@ -300,4 +300,22 @@ export class NativeDateAdapter extends DateAdapter<Date> {
300300  private  _stripDirectionalityCharacters ( str : string )  { 
301301    return  str . replace ( / [ \u200e \u200f ] / g,  '' ) ; 
302302  } 
303+ 
304+   /** 
305+    * When converting Date object to string, javascript built-in functions may return wrong 
306+    * results because it applies its internal DST rules. The DST rules around the world change 
307+    * very frequently, and the current valid rule is not always valid in previous years though. 
308+    * We work around this problem building a new Date object which has its internal UTC 
309+    * representation with the local date and time. 
310+    * @param  dtf Intl.DateTimeFormat object, containg the desired string format. It must have 
311+    *    timeZone set to 'utc' to work fine. 
312+    * @param  date Date from which we want to get the string representation according to dtf 
313+    * @returns  A Date object with its UTC representation based on the passed in date info 
314+    */ 
315+   private  _format ( dtf : Intl . DateTimeFormat ,  date : Date )  { 
316+     const  d  =  new  Date ( Date . UTC ( 
317+         date . getFullYear ( ) ,  date . getMonth ( ) ,  date . getDate ( ) ,  date . getHours ( ) , 
318+         date . getMinutes ( ) ,  date . getSeconds ( ) ,  date . getMilliseconds ( ) ) ) ; 
319+     return  dtf . format ( d ) ; 
320+   } 
303321} 
0 commit comments