fix(docs-infra): correctly display event dates on all timezones (#41053)

Previously, the event dates displayed on the angular.io "Events" page
(`/events`) was off by one day on timezones with a negative offset from
UTC. See
https://github.com/angular/angular/pull/41050#issuecomment-788958888.

This commit fixes it by using the `getUTC*` methods of the `Date` object
to extract the date info, which are not affected by the user's timezone.

PR Close #41053
This commit is contained in:
George Kalpakas 2021-03-02 18:57:26 +02:00 committed by Zach Arend
parent 5eab6e14f1
commit cb16035fd3
4 changed files with 104 additions and 76 deletions

View File

@ -161,6 +161,7 @@
"rimraf": "^2.6.1", "rimraf": "^2.6.1",
"semver": "^5.3.0", "semver": "^5.3.0",
"shelljs": "^0.8.4", "shelljs": "^0.8.4",
"timezone-mock": "^1.1.3",
"tree-kill": "^1.1.0", "tree-kill": "^1.1.0",
"ts-node": "^8.4.1", "ts-node": "^8.4.1",
"tslint": "~6.1.0", "tslint": "~6.1.0",

View File

@ -1,5 +1,6 @@
import { Injector } from '@angular/core'; import { Injector } from '@angular/core';
import { Subject } from 'rxjs'; import { Subject } from 'rxjs';
import * as tzMock from 'timezone-mock';
import { Duration, Event, EventsComponent } from './events.component'; import { Duration, Event, EventsComponent } from './events.component';
import { EventsService } from './events.service'; import { EventsService } from './events.service';
@ -132,6 +133,20 @@ describe('EventsComponent', () => {
}); });
describe('getEventDates()', () => { describe('getEventDates()', () => {
// Test on different timezones to ensure that event dates are processed correctly regardless of
// the user's local time.
const timezones: tzMock.TimeZone[] = [
'Australia/Adelaide', // UTC+9.5/10.5
'Brazil/East', // UTC-3
'UTC', // UTC
];
for (const tz of timezones) {
describe(`on timezone ${tz}`, () => {
// NOTE: `timezone-mock` does not work correctly if used together with Jasmine's mock clock.
beforeEach(() => tzMock.register(tz));
afterEach(() => tzMock.unregister());
describe('(without workshops)', () => { describe('(without workshops)', () => {
it('should correctly format the main event date', () => { it('should correctly format the main event date', () => {
const testEvent = createMockEvent('Test', {start: '2020-06-20', end: '2020-06-20'}); const testEvent = createMockEvent('Test', {start: '2020-06-20', end: '2020-06-20'});
@ -147,6 +162,11 @@ describe('EventsComponent', () => {
const testEvent = createMockEvent('Test', {start: '2019-10-30', end: '2019-11-01'}); const testEvent = createMockEvent('Test', {start: '2019-10-30', end: '2019-11-01'});
expect(component.getEventDates(testEvent)).toBe('October 30 - November 1, 2019'); expect(component.getEventDates(testEvent)).toBe('October 30 - November 1, 2019');
}); });
it('should correctly format event dates at the beginning/end of the year', () => {
const testEvent = createMockEvent('Test', {start: '2021-01-01', end: '2021-12-31'});
expect(component.getEventDates(testEvent)).toBe('January 1 - December 31, 2021');
});
}); });
describe('(with workshops)', () => { describe('(with workshops)', () => {
@ -213,6 +233,8 @@ describe('EventsComponent', () => {
}); });
}); });
}); });
}
});
// Helpers // Helpers
class TestEventsService { class TestEventsService {

View File

@ -72,7 +72,7 @@ export class EventsComponent implements OnInit {
// If no work shop date create conference date string // If no work shop date create conference date string
dateString = processDate(event.date); dateString = processDate(event.date);
} }
dateString = `${dateString}, ${new Date(event.date.end).getFullYear()}`; dateString = `${dateString}, ${new Date(event.date.end).getUTCFullYear()}`;
return dateString; return dateString;
} }
} }
@ -83,14 +83,14 @@ function processDate(dates: Duration) {
const endDate = new Date(dates.end); const endDate = new Date(dates.end);
// Create a date string in the start like January 31 // Create a date string in the start like January 31
let processedDate = `${MONTHS[startDate.getMonth()]} ${startDate.getDate()}`; let processedDate = `${MONTHS[startDate.getUTCMonth()]} ${startDate.getUTCDate()}`;
// If they are in different months add the string '- February 2' Making the final string January 31 - February 2 // If they are in different months add the string '- February 2' Making the final string January 31 - February 2
if (startDate.getMonth() !== endDate.getMonth()) { if (startDate.getUTCMonth() !== endDate.getUTCMonth()) {
processedDate = `${processedDate} - ${MONTHS[endDate.getMonth()]} ${endDate.getDate()}`; processedDate = `${processedDate} - ${MONTHS[endDate.getUTCMonth()]} ${endDate.getUTCDate()}`;
} else if (startDate.getDate() !== endDate.getDate()) { } else if (startDate.getUTCDate() !== endDate.getUTCDate()) {
// If not add - date eg it will make // January 30-31 // If not add - date eg it will make // January 30-31
processedDate = `${processedDate}-${endDate.getDate()}`; processedDate = `${processedDate}-${endDate.getUTCDate()}`;
} }
return processedDate; return processedDate;

View File

@ -13168,6 +13168,11 @@ timers-ext@^0.1.5:
es5-ext "~0.10.46" es5-ext "~0.10.46"
next-tick "1" next-tick "1"
timezone-mock@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/timezone-mock/-/timezone-mock-1.1.3.tgz#f5ca25befec2cdd2d64c07ee7a5293275c06b97e"
integrity sha512-r+fz9M1tflNkF6mJK0DwmlFyNWeSCXxZ68pu2Bv+DddIHK/czOZwnasEql17VfHqP/OcZRuPq/qi6wm7eQmQow==
timsort@^0.3.0: timsort@^0.3.0:
version "0.3.0" version "0.3.0"
resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4"