This is an automated email from the ASF dual-hosted git repository.

bbovenzi pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new df37268410b Fix UI crash by validating unresolvable Windows PT 
timezone (#75723)
df37268410b is described below

commit df37268410b9e9d82298d719655b4273a6e33ac0
Author: Basant_Jamwal <[email protected]>
AuthorDate: Tue Oct 27 20:55:00 2026 +0530

    Fix UI crash by validating unresolvable Windows PT timezone (#75723)
    
    * 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
---
 .../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 };
 

Reply via email to