mirror of
https://github.com/lukevella/rallly.git
synced 2025-07-24 19:58:04 +02:00
🐛 Fix fallback behaviour for unrecognized timezones (#1241)
This commit is contained in:
parent
7bc978b87a
commit
2798ba65ce
3 changed files with 63 additions and 25 deletions
|
@ -19,24 +19,59 @@ export function parseIanaTimezone(timezone: string): {
|
|||
}
|
||||
|
||||
export function getBrowserTimeZone() {
|
||||
const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
return resolveGeographicTimeZone(timeZone);
|
||||
const timeZone = dayjs.tz.guess();
|
||||
return normalizeTimeZone(timeZone);
|
||||
}
|
||||
|
||||
export function resolveGeographicTimeZone(timezone: string) {
|
||||
const tz = supportedTimeZones.find((tz) => tz === timezone);
|
||||
function getTimeZoneOffset(timeZone: string) {
|
||||
try {
|
||||
return dayjs().tz(timeZone).utcOffset();
|
||||
} catch (e) {
|
||||
console.error(`Failed to resolve timezone ${timeZone}`);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
function isFixedOffsetTimeZone(timeZone: string) {
|
||||
return (
|
||||
timeZone.toLowerCase().startsWith("etc") ||
|
||||
timeZone.toLowerCase().startsWith("gmt") ||
|
||||
timeZone.toLowerCase().startsWith("utc")
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a timezone, this function returns a normalized timezone
|
||||
* that is supported by the application. If the timezone is not
|
||||
* recognized, it will return a timezone in the same continent
|
||||
* with the same offset.
|
||||
* @param timeZone
|
||||
* @returns
|
||||
*/
|
||||
export function normalizeTimeZone(timeZone: string) {
|
||||
let tz = supportedTimeZones.find((tz) => tz === timeZone);
|
||||
|
||||
if (tz) {
|
||||
return tz;
|
||||
}
|
||||
|
||||
const timeZoneOffset = getTimeZoneOffset(timeZone);
|
||||
|
||||
if (!isFixedOffsetTimeZone(timeZone)) {
|
||||
// Find a timezone in the same continent with the same offset
|
||||
const [continent] = timeZone.split("/");
|
||||
const sameContinentTimeZones = supportedTimeZones.filter((tz) =>
|
||||
tz.startsWith(continent),
|
||||
);
|
||||
tz = sameContinentTimeZones.find((tz) => {
|
||||
return dayjs().tz(tz, true).utcOffset() === timeZoneOffset;
|
||||
});
|
||||
}
|
||||
|
||||
if (!tz) {
|
||||
// find nearest timezone with the same offset
|
||||
let offset = 0;
|
||||
try {
|
||||
offset = dayjs().tz(timezone).utcOffset();
|
||||
} catch (e) {
|
||||
console.error(`Failed to resolve timezone ${timezone}`);
|
||||
}
|
||||
return supportedTimeZones.find((tz) => {
|
||||
return dayjs().tz(tz, true).utcOffset() === offset;
|
||||
})!;
|
||||
tz = supportedTimeZones.find((tz) => {
|
||||
return getTimeZoneOffset(tz) === timeZoneOffset;
|
||||
})!; // We assume there has to be a timezone with the same offset
|
||||
}
|
||||
|
||||
return tz;
|
||||
|
|
|
@ -5,34 +5,40 @@ import { describe, expect, it } from "vitest";
|
|||
|
||||
import { supportedTimeZones } from "@/utils/supported-time-zones";
|
||||
|
||||
import { resolveGeographicTimeZone } from "./date-time-utils";
|
||||
import { normalizeTimeZone } from "./date-time-utils";
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
describe("resolveGeographicTimezone", () => {
|
||||
describe("Normalize Time Zone", () => {
|
||||
it("should return same timezone when given a geographic timezone", () => {
|
||||
const browserTimeZone = resolveGeographicTimeZone("Europe/London");
|
||||
const browserTimeZone = normalizeTimeZone("Europe/London");
|
||||
|
||||
// Assert that the browser time zone is one of the supported time zones
|
||||
expect(browserTimeZone).toBe("Europe/London");
|
||||
});
|
||||
it("should return a supported timezone when given a fixed offset timezone", () => {
|
||||
const browserTimeZone = resolveGeographicTimeZone("Etc/GMT-1");
|
||||
const browserTimeZone = normalizeTimeZone("Etc/GMT-1");
|
||||
|
||||
// Assert that the browser time zone is one of the supported time zones
|
||||
expect(supportedTimeZones.includes(browserTimeZone)).toBe(true);
|
||||
});
|
||||
it("should return a supported timezone when given GMT", () => {
|
||||
const browserTimeZone = resolveGeographicTimeZone("GMT");
|
||||
const browserTimeZone = normalizeTimeZone("GMT");
|
||||
|
||||
// Assert that the browser time zone is one of the supported time zones
|
||||
expect(supportedTimeZones.includes(browserTimeZone)).toBe(true);
|
||||
});
|
||||
it("should return a supported timezone when given UTC", () => {
|
||||
const browserTimeZone = resolveGeographicTimeZone("UTC");
|
||||
const browserTimeZone = normalizeTimeZone("UTC");
|
||||
|
||||
// Assert that the browser time zone is one of the supported time zones
|
||||
expect(supportedTimeZones.includes(browserTimeZone)).toBe(true);
|
||||
});
|
||||
|
||||
it("should return a valid timezone in the same continent when not recognized", () => {
|
||||
const browserTimeZone = normalizeTimeZone("Asia/Kolkata");
|
||||
|
||||
expect(browserTimeZone).toBe("Asia/Calcutta");
|
||||
});
|
||||
});
|
||||
|
|
|
@ -17,10 +17,7 @@ import * as React from "react";
|
|||
import { useAsync } from "react-use";
|
||||
|
||||
import { usePreferences } from "@/contexts/preferences";
|
||||
import {
|
||||
getBrowserTimeZone,
|
||||
resolveGeographicTimeZone,
|
||||
} from "@/utils/date-time-utils";
|
||||
import { getBrowserTimeZone, normalizeTimeZone } from "@/utils/date-time-utils";
|
||||
|
||||
import { useRequiredContext } from "../components/use-required-context";
|
||||
|
||||
|
@ -213,7 +210,7 @@ export const DayjsProvider: React.FunctionComponent<{
|
|||
const preferredTimeZone = React.useMemo(
|
||||
() =>
|
||||
config?.timeZone
|
||||
? resolveGeographicTimeZone(config?.timeZone)
|
||||
? normalizeTimeZone(config?.timeZone)
|
||||
: getBrowserTimeZone(),
|
||||
[config?.timeZone],
|
||||
);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue