fix(common): format day-periods that cross midnight (#36611)
When formatting a time with the `b` or `B` format codes, the rendered string was not correctly handling day periods that spanned midnight. Instead the logic was falling back to the default case of `AM`. Now the logic has been updated so that it matches times that are within a day period that spans midnight, so it will now render the correct output, such as `at night` in the case of English. Applications that are using either `formatDate()` or `DatePipe` and any of the `b` or `B` format codes will be affected by this change. Fixes #36566 PR Close #36611
This commit is contained in:
		
							parent
							
								
									074266b896
								
							
						
					
					
						commit
						c6e5fc4fbe
					
				| @ -277,26 +277,40 @@ function getDateTranslation( | |||||||
|       if (extended) { |       if (extended) { | ||||||
|         const rules = getLocaleExtraDayPeriodRules(locale); |         const rules = getLocaleExtraDayPeriodRules(locale); | ||||||
|         const dayPeriods = getLocaleExtraDayPeriods(locale, form, width); |         const dayPeriods = getLocaleExtraDayPeriods(locale, form, width); | ||||||
|         let result; |         const index = rules.findIndex(rule => { | ||||||
|         rules.forEach((rule: Time|[Time, Time], index: number) => { |  | ||||||
|           if (Array.isArray(rule)) { |           if (Array.isArray(rule)) { | ||||||
|             // morning, afternoon, evening, night
 |             // morning, afternoon, evening, night
 | ||||||
|             const {hours: hoursFrom, minutes: minutesFrom} = rule[0]; |             const [from, to] = rule; | ||||||
|             const {hours: hoursTo, minutes: minutesTo} = rule[1]; |             const afterFrom = currentHours >= from.hours && currentMinutes >= from.minutes; | ||||||
|             if (currentHours >= hoursFrom && currentMinutes >= minutesFrom && |             const beforeTo = | ||||||
|                 (currentHours < hoursTo || |                 (currentHours < to.hours || | ||||||
|                  (currentHours === hoursTo && currentMinutes < minutesTo))) { |                  (currentHours === to.hours && currentMinutes < to.minutes)); | ||||||
|               result = dayPeriods[index]; |             // We must account for normal rules that span a period during the day (e.g. 6am-9am)
 | ||||||
|  |             // where `from` is less (earlier) than `to`. But also rules that span midnight (e.g.
 | ||||||
|  |             // 10pm - 5am) where `from` is greater (later!) than `to`.
 | ||||||
|  |             //
 | ||||||
|  |             // In the first case the current time must be BOTH after `from` AND before `to`
 | ||||||
|  |             // (e.g. 8am is after 6am AND before 10am).
 | ||||||
|  |             //
 | ||||||
|  |             // In the second case the current time must be EITHER after `from` OR before `to`
 | ||||||
|  |             // (e.g. 4am is before 5am but not after 10pm; and 11pm is not before 5am but it is
 | ||||||
|  |             // after 10pm).
 | ||||||
|  |             if (from.hours < to.hours) { | ||||||
|  |               if (afterFrom && beforeTo) { | ||||||
|  |                 return true; | ||||||
|  |               } | ||||||
|  |             } else if (afterFrom || beforeTo) { | ||||||
|  |               return true; | ||||||
|             } |             } | ||||||
|           } else {  // noon or midnight
 |           } else {  // noon or midnight
 | ||||||
|             const {hours, minutes} = rule; |             if (rule.hours === currentHours && rule.minutes === currentMinutes) { | ||||||
|             if (hours === currentHours && minutes === currentMinutes) { |               return true; | ||||||
|               result = dayPeriods[index]; |  | ||||||
|             } |             } | ||||||
|           } |           } | ||||||
|  |           return false; | ||||||
|         }); |         }); | ||||||
|         if (result) { |         if (index !== -1) { | ||||||
|           return result; |           return dayPeriods[index]; | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|       // if no rules for the day periods, we use am/pm by default
 |       // if no rules for the day periods, we use am/pm by default
 | ||||||
|  | |||||||
| @ -202,6 +202,19 @@ describe('Format date', () => { | |||||||
|         BBBBB: 'mi', |         BBBBB: 'mi', | ||||||
|       }; |       }; | ||||||
| 
 | 
 | ||||||
|  |       const midnightCrossingPeriods: any = { | ||||||
|  |         b: 'night', | ||||||
|  |         bb: 'night', | ||||||
|  |         bbb: 'night', | ||||||
|  |         bbbb: 'night', | ||||||
|  |         bbbbb: 'night', | ||||||
|  |         B: 'at night', | ||||||
|  |         BB: 'at night', | ||||||
|  |         BBB: 'at night', | ||||||
|  |         BBBB: 'at night', | ||||||
|  |         BBBBB: 'at night', | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|       Object.keys(dateFixtures).forEach((pattern: string) => { |       Object.keys(dateFixtures).forEach((pattern: string) => { | ||||||
|         expectDateFormatAs(date, pattern, dateFixtures[pattern]); |         expectDateFormatAs(date, pattern, dateFixtures[pattern]); | ||||||
|       }); |       }); | ||||||
| @ -209,6 +222,11 @@ describe('Format date', () => { | |||||||
|       Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => { |       Object.keys(isoStringWithoutTimeFixtures).forEach((pattern: string) => { | ||||||
|         expectDateFormatAs(isoStringWithoutTime, pattern, isoStringWithoutTimeFixtures[pattern]); |         expectDateFormatAs(isoStringWithoutTime, pattern, isoStringWithoutTimeFixtures[pattern]); | ||||||
|       }); |       }); | ||||||
|  | 
 | ||||||
|  |       const nightTime = new Date(2015, 5, 15, 2, 3, 1, 550); | ||||||
|  |       Object.keys(midnightCrossingPeriods).forEach(pattern => { | ||||||
|  |         expectDateFormatAs(nightTime, pattern, midnightCrossingPeriods[pattern]); | ||||||
|  |       }); | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
|     it('should format with timezones', () => { |     it('should format with timezones', () => { | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user