Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions packages/@internationalized/date/src/conversion.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import {AnyCalendarDate, AnyDateTime, AnyTime, Calendar, DateFields, Disambiguat
import {CalendarDate, CalendarDateTime, Time, ZonedDateTime} from './CalendarDate';
import {constrain} from './manipulation';
import {getExtendedYear, GregorianCalendar} from './calendars/GregorianCalendar';
import {getLocalTimeZone, isEqualCalendar} from './queries';
import {getLocalTimeZone, isEqualCalendar, isLocalTimeZoneOverridden} from './queries';
import {Mutable} from './utils';

export function epochFromDate(date: AnyDateTime): number {
Expand All @@ -42,7 +42,7 @@ export function getTimeZoneOffset(ms: number, timeZone: string): number {
}

// Fast path: for local timezone after 1970, use native Date.
if (ms > 0 && timeZone === getLocalTimeZone()) {
if (ms > 0 && timeZone === getLocalTimeZone() && !isLocalTimeZoneOverridden()) {
return new Date(ms).getTimezoneOffset() * -60 * 1000;
}

Expand Down Expand Up @@ -124,7 +124,7 @@ export function toAbsolute(date: CalendarDate | CalendarDateTime, timeZone: stri
}

// Fast path: if the time zone is the local timezone and disambiguation is compatible, use native Date.
if (timeZone === getLocalTimeZone() && disambiguation === 'compatible') {
if (timeZone === getLocalTimeZone() && disambiguation === 'compatible' && !isLocalTimeZoneOverridden()) {
dateTime = toCalendar(dateTime, new GregorianCalendar());

// Don't use Date constructor here because two-digit years are interpreted in the 20th century.
Expand Down
1 change: 1 addition & 0 deletions packages/@internationalized/date/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ export {
getLocalTimeZone,
setLocalTimeZone,
resetLocalTimeZone,
isLocalTimeZoneOverridden,
startOfMonth,
startOfWeek,
startOfYear,
Expand Down
8 changes: 8 additions & 0 deletions packages/@internationalized/date/src/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ export function getHoursInDay(a: CalendarDate, timeZone: string): number {
}

let localTimeZone: string | null = null;
let localTimeZoneOverridden = false;

/** Returns the time zone identifier for the current user. */
export function getLocalTimeZone(): string {
Expand All @@ -143,11 +144,18 @@ export function getLocalTimeZone(): string {
/** Sets the time zone identifier for the current user. */
export function setLocalTimeZone(timeZone: string): void {
localTimeZone = timeZone;
localTimeZoneOverridden = true;
}

/** Resets the time zone identifier for the current user. */
export function resetLocalTimeZone(): void {
localTimeZone = null;
localTimeZoneOverridden = false;
}

/** Returns whether the local time zone has been overridden via setLocalTimeZone. */
export function isLocalTimeZoneOverridden(): boolean {
return localTimeZoneOverridden;
}

/** Returns the first date of the month for the given date. */
Expand Down
26 changes: 25 additions & 1 deletion packages/@internationalized/date/tests/conversion.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
* governing permissions and limitations under the License.
*/

import {BuddhistCalendar, CalendarDate, CalendarDateTime, EthiopicAmeteAlemCalendar, EthiopicCalendar, GregorianCalendar, HebrewCalendar, IndianCalendar, IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar, JapaneseCalendar, PersianCalendar, TaiwanCalendar, Time, toCalendar, toCalendarDate, toCalendarDateTime, toTime, ZonedDateTime} from '..';
import {BuddhistCalendar, CalendarDate, CalendarDateTime, EthiopicAmeteAlemCalendar, EthiopicCalendar, GregorianCalendar, HebrewCalendar, IndianCalendar, IslamicCivilCalendar, IslamicTabularCalendar, IslamicUmalquraCalendar, JapaneseCalendar, PersianCalendar, TaiwanCalendar, Time, toCalendar, toCalendarDate, toCalendarDateTime, toTime, ZonedDateTime, setLocalTimeZone, resetLocalTimeZone} from '..';
import {Custom454Calendar} from './customCalendarImpl';
import {fromAbsolute, possibleAbsolutes, toAbsolute, toDate} from '../src/conversion';

Expand Down Expand Up @@ -522,4 +522,28 @@ describe('CalendarDate conversion', function () {
expect(toTime(dateTime)).toEqual(new Time(8, 23, 10, 80));
});
});

describe('setLocalTimeZone interaction with fast paths', function () {
afterEach(() => {
resetLocalTimeZone();
});

it('fromAbsolute should return the correct offset when local timezone is overridden', function () {
// Etc/GMT-10 means UTC+10
setLocalTimeZone('Etc/GMT-10');
let ms = Date.UTC(2020, 5, 15, 12, 0, 0); // 2020-06-15T12:00:00Z
let zdt = fromAbsolute(ms, 'Etc/GMT-10');
expect(zdt.hour).toBe(22); // 12:00 UTC + 10 = 22:00
expect(zdt.offset).toBe(10 * 60 * 60 * 1000);
});

it('toAbsolute should return the correct epoch when local timezone is overridden', function () {
// Etc/GMT-10 means UTC+10
setLocalTimeZone('Etc/GMT-10');
let date = new CalendarDateTime(2020, 6, 15, 22, 0, 0);
let ms = toAbsolute(date, 'Etc/GMT-10');
// 22:00 in UTC+10 = 12:00 UTC
expect(ms).toBe(Date.UTC(2020, 5, 15, 12, 0, 0));
});
});
});
23 changes: 23 additions & 0 deletions packages/@internationalized/date/tests/queries.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
maxDate,
minDate,
PersianCalendar,
isLocalTimeZoneOverridden,
resetLocalTimeZone,
setLocalTimeZone,
startOfMonth,
Expand Down Expand Up @@ -371,4 +372,26 @@ describe('queries', function () {
expect(getLocalTimeZone()).toBe(systemTimeZone);
});
});

describe('isLocalTimeZoneOverridden', function () {
afterEach(() => {
resetLocalTimeZone();
});

it('returns false by default', function () {
expect(isLocalTimeZoneOverridden()).toBe(false);
});

it('returns true after setLocalTimeZone', function () {
setLocalTimeZone('America/Denver');
expect(isLocalTimeZoneOverridden()).toBe(true);
});

it('returns false after resetLocalTimeZone', function () {
setLocalTimeZone('America/Denver');
expect(isLocalTimeZoneOverridden()).toBe(true);
resetLocalTimeZone();
expect(isLocalTimeZoneOverridden()).toBe(false);
});
});
});