This is an automated email from the ASF dual-hosted git repository.
bbovenzi pushed a commit to branch v3-4-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-4-test by this push:
new ee42ee6e059 [v3-4-test] Fix UI crash by validating unresolvable
Windows PT timezone (#75723) (#75800)
ee42ee6e059 is described below
commit ee42ee6e059bf020384ad3a3dff66ad3a8eef798
Author: github-actions[bot]
<41898282+github-actions[bot]@users.noreply.github.com>
AuthorDate: Tue Oct 27 16:51:30 2026 -0400
[v3-4-test] Fix UI crash by validating unresolvable Windows PT timezone
(#75723) (#75800)
* Fix UI crash from unresolvable Windows PT timezone
Validate the stored/system timezone before using it, falling back
to UTC when it cannot be resolved (e.g. Windows' new unified 'PT'
zone name). Prevents a TypeError crash across the UI.
Closes #75697
* Fix formatting: correct indentation and add missing newline
* Add Apache license header to new test file
* Remove extra blank line after license header
(cherry picked from commit df37268410b9e9d82298d719655b4273a6e33ac0)
Co-authored-by: Basant_Jamwal <[email protected]>
---
.../src/context/timezone/TimezoneProvider.test.tsx | 59 ++++++++++++++++++++++
.../ui/src/context/timezone/TimezoneProvider.tsx | 17 ++++++-
2 files changed, 75 insertions(+), 1 deletion(-)
diff --git
a/airflow-core/src/airflow/ui/src/context/timezone/TimezoneProvider.test.tsx
b/airflow-core/src/airflow/ui/src/context/timezone/TimezoneProvider.test.tsx
new file mode 100644
index 00000000000..6e5a658a1dc
--- /dev/null
+++ b/airflow-core/src/airflow/ui/src/context/timezone/TimezoneProvider.test.tsx
@@ -0,0 +1,59 @@
+/*!
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import { renderHook } from "@testing-library/react";
+import { describe, it, expect, beforeEach } from "vitest";
+
+import { TimezoneProvider } from "./TimezoneProvider";
+import { useTimezone } from "./useTimezone";
+
+describe("TimezoneProvider falls back on invalid stored timezone", () => {
+ beforeEach(() => {
+ localStorage.clear();
+ });
+
+ it("falls back to UTC when localStorage has an invalid value like 'PT'", ()
=> {
+ localStorage.setItem("timezone", JSON.stringify("PT"));
+
+ const { result } = renderHook(() => useTimezone(), {
+ wrapper: TimezoneProvider,
+ });
+
+ expect(result.current.selectedTimezone).toBe("UTC");
+ });
+
+ it("falls back to UTC when localStorage has an empty string", () => {
+ localStorage.setItem("timezone", JSON.stringify(""));
+
+ const { result } = renderHook(() => useTimezone(), {
+ wrapper: TimezoneProvider,
+ });
+
+ expect(result.current.selectedTimezone).toBe("UTC");
+ });
+
+ it("keeps a valid stored timezone", () => {
+ localStorage.setItem("timezone", JSON.stringify("America/New_York"));
+
+ const { result } = renderHook(() => useTimezone(), {
+ wrapper: TimezoneProvider,
+ });
+
+ expect(result.current.selectedTimezone).toBe("America/New_York");
+ });
+});
diff --git
a/airflow-core/src/airflow/ui/src/context/timezone/TimezoneProvider.tsx
b/airflow-core/src/airflow/ui/src/context/timezone/TimezoneProvider.tsx
index f64470e44cc..077fcda2077 100644
--- a/airflow-core/src/airflow/ui/src/context/timezone/TimezoneProvider.tsx
+++ b/airflow-core/src/airflow/ui/src/context/timezone/TimezoneProvider.tsx
@@ -24,10 +24,25 @@ import { TIMEZONE_KEY } from "src/constants/localStorage";
import { TimezoneContext, type TimezoneContextType } from "./Context";
+const isValidTimezone = (tz: string | undefined): boolean => {
+ if (tz === undefined || tz === "") {
+ return false;
+ }
+
+ try {
+ Intl.DateTimeFormat(undefined, { timeZone: tz });
+
+ return true;
+ } catch {
+ return false;
+ }
+};
+
export const TimezoneProvider = ({ children }: PropsWithChildren) => {
const systemTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
- const [selectedTimezone, setSelectedTimezone] =
useLocalStorage(TIMEZONE_KEY, systemTimezone);
+ const [storedTimezone, setSelectedTimezone] = useLocalStorage(TIMEZONE_KEY,
systemTimezone);
+ const selectedTimezone = isValidTimezone(storedTimezone) ? storedTimezone :
"UTC";
const value: TimezoneContextType = { selectedTimezone, setSelectedTimezone };