Skip to content
Merged
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
9 changes: 7 additions & 2 deletions src/TIMEZONES.ts
Original file line number Diff line number Diff line change
Expand Up @@ -427,7 +427,7 @@ const TIMEZONES = [
* The timezones supported in browser and on native devices differ, so we must map each timezone to its supported equivalent.
* Data sourced from https://en.wikipedia.org/wiki/List_of_tz_database_time_zones
*/
const timezoneBackwardMap: Record<string, TupleToUnion<typeof TIMEZONES>> = {
const timezoneBackwardToNewMap: Record<string, TupleToUnion<typeof TIMEZONES>> = {
'Africa/Asmera': 'Africa/Nairobi',
'Africa/Timbuktu': 'Africa/Abidjan',
'America/Argentina/ComodRivadavia': 'America/Argentina/Catamarca',
Expand Down Expand Up @@ -564,6 +564,11 @@ const timezoneBackwardMap: Record<string, TupleToUnion<typeof TIMEZONES>> = {
WET: 'Europe/Lisbon',
};

export {timezoneBackwardMap};
const timezoneNewToBackwardMap = Object.fromEntries(Object.entries(timezoneBackwardToNewMap).map(([oldTimezone, newTimezone]) => [newTimezone, oldTimezone])) as Record<
TupleToUnion<typeof TIMEZONES>,
string
>;

export {timezoneBackwardToNewMap, timezoneNewToBackwardMap};

export default TIMEZONES;
30 changes: 24 additions & 6 deletions src/libs/DateUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,14 @@ import type {ValueOf} from 'type-fest';
import type {LocaleContextProps} from '@components/LocaleContextProvider';
import CONST from '@src/CONST';
import ONYXKEYS from '@src/ONYXKEYS';
import {timezoneBackwardMap} from '@src/TIMEZONES';
import {timezoneBackwardToNewMap, timezoneNewToBackwardMap} from '@src/TIMEZONES';
import type {SelectedTimezone, Timezone} from '@src/types/onyx/PersonalDetails';
import {setCurrentDate} from './actions/CurrentDate';
import {setNetworkLastOffline} from './actions/Network';
import {translate, translateLocal} from './Localize';
import BaseLocaleListener from './Localize/LocaleListener/BaseLocaleListener';
import Log from './Log';
import memoize from './memoize';

type CustomStatusTypes = ValueOf<typeof CONST.CUSTOM_STATUS_TYPES>;
type Locale = ValueOf<typeof CONST.LOCALES>;
Expand Down Expand Up @@ -147,7 +148,8 @@ function setLocale(localeString: Locale) {
* Gets the user's stored time zone NVP and returns a localized
* Date object for the given ISO-formatted datetime string
*/
function getLocalDateFromDatetime(locale: Locale, datetime?: string, currentSelectedTimezone: SelectedTimezone = timezone.selected): Date {
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
function getLocalDateFromDatetime(locale: Locale, datetime?: string, currentSelectedTimezone: string | SelectedTimezone = timezone.selected): Date {
setLocale(locale);
if (!datetime) {
const res = toZonedTime(new Date(), currentSelectedTimezone);
Expand Down Expand Up @@ -214,6 +216,22 @@ function isYesterday(date: Date, timeZone: SelectedTimezone): boolean {
return isSameDay(date, yesterdayInTimeZone);
}

/**
* We have to fall back to older timezone names for native platforms that do not ship with newer timezone names to avoid a crash.
* Memoize to prevent unnecessary calculation as timezone support will not change on runtime on a platform.
*/
// eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents
const fallbackToSupportedTimezone = memoize((timezoneInput: SelectedTimezone): SelectedTimezone | string => {
try {
const date = new Date();
const testDate = toZonedTime(date, timezoneInput);
format(testDate, CONST.DATE.FNS_FORMAT_STRING);
return timezoneInput;
} catch (error) {
return timezoneNewToBackwardMap[timezoneInput];
}
});

/**
* Formats an ISO-formatted datetime string to local date and time string
*
Expand All @@ -223,7 +241,7 @@ function isYesterday(date: Date, timeZone: SelectedTimezone): boolean {
* Jan 20, 2019 at 5:30 PM anything over 1 year ago
*/
function datetimeToCalendarTime(locale: Locale, datetime: string, includeTimeZone = false, currentSelectedTimezone: SelectedTimezone = timezone.selected, isLowercase = false): string {
const date = getLocalDateFromDatetime(locale, datetime, currentSelectedTimezone);
const date = getLocalDateFromDatetime(locale, datetime, fallbackToSupportedTimezone(currentSelectedTimezone));
const tz = includeTimeZone ? ' [UTC]Z' : '';
let todayAt = translate(locale, 'common.todayAt');
let tomorrowAt = translate(locale, 'common.tomorrowAt');
Expand Down Expand Up @@ -757,15 +775,15 @@ function formatWithUTCTimeZone(datetime: string, dateFormat: string = CONST.DATE
/**
*
* @param timezone
* function format unsupported timezone to supported timezone
* Convert unsupported old timezone to app supported timezone
* @returns Timezone
*/
function formatToSupportedTimezone(timezoneInput: Timezone): Timezone {
if (!timezoneInput?.selected) {
return timezoneInput;
}
return {
selected: timezoneBackwardMap[timezoneInput.selected] ?? timezoneInput.selected,
selected: timezoneBackwardToNewMap[timezoneInput.selected] ?? timezoneInput.selected,
automatic: timezoneInput.automatic,
};
}
Expand Down Expand Up @@ -967,7 +985,7 @@ const formatInTimeZoneWithFallback: typeof formatInTimeZone = (date, timeZone, f
// On macOs and iOS devices some platform use deprecated old timezone values which results in invalid time string error.
// Try with backward timezone values on error.
} catch {
return formatInTimeZone(date, timezoneBackwardMap[timeZone], formatStr, options);
return formatInTimeZone(date, timezoneNewToBackwardMap[timeZone as SelectedTimezone], formatStr, options);
}
};

Expand Down