This is an automated email from the ASF dual-hosted git repository.
rahulvats pushed a commit to branch v3-1-test
in repository https://gitbox.apache.org/repos/asf/airflow.git
The following commit(s) were added to refs/heads/v3-1-test by this push:
new 88f136fe903 fix(ui): use ISO dates in Gantt chart for cross-browser
consistency (#61250) (#62784)
88f136fe903 is described below
commit 88f136fe90347d29b6114a9a968d04533b2f3b6f
Author: Pierre Jeambrun <[email protected]>
AuthorDate: Tue Mar 3 13:10:45 2026 +0100
fix(ui): use ISO dates in Gantt chart for cross-browser consistency
(#61250) (#62784)
(cherry picked from commit 705107621ca10fed635b0374ab1b9ca46b11766f)
Co-authored-by: yuseok89 <[email protected]>
---
.../src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx
b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx
index 54d2c476b41..2dc9ec6c0f6 100644
--- a/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx
+++ b/airflow-core/src/airflow/ui/src/layouts/Details/Gantt/Gantt.tsx
@@ -52,7 +52,6 @@ import { useGridStructure } from
"src/queries/useGridStructure";
import { useGridTiSummaries } from "src/queries/useGridTISummaries";
import { getComputedCSSVariableValue } from "src/theme";
import { isStatePending, useAutoRefresh } from "src/utils";
-import { DEFAULT_DATETIME_FORMAT_WITH_TZ, formatDate } from
"src/utils/datetimeUtils";
import { createHandleBarClick, createHandleBarHover, createChartOptions } from
"./utils";
@@ -144,8 +143,6 @@ export const Gantt = ({ limit, runType, triggeringUser }:
Props) => {
const isLoading = runsLoading || structureLoading || summariesLoading ||
tiLoading;
- const currentTime =
dayjs().tz(selectedTimezone).format(DEFAULT_DATETIME_FORMAT_WITH_TZ);
-
const data = useMemo(() => {
if (isLoading || runId === "") {
return [];
@@ -159,15 +156,15 @@ export const Gantt = ({ limit, runType, triggeringUser }:
Props) => {
const gridSummary = gridSummaries.find((ti) => ti.task_id === node.id);
if ((node.isGroup ?? node.is_mapped) && gridSummary) {
- // Use min/max times from grid summary
+ // Use min/max times from grid summary; ISO so time scale and bar
positions render consistently across browsers
return {
isGroup: node.isGroup,
isMapped: node.is_mapped,
state: gridSummary.state,
taskId: gridSummary.task_id,
x: [
- formatDate(gridSummary.min_start_date, selectedTimezone,
DEFAULT_DATETIME_FORMAT_WITH_TZ),
- formatDate(gridSummary.max_end_date, selectedTimezone,
DEFAULT_DATETIME_FORMAT_WITH_TZ),
+ dayjs(gridSummary.min_start_date).toISOString(),
+ dayjs(gridSummary.max_end_date).toISOString(),
],
y: gridSummary.task_id,
};
@@ -177,17 +174,14 @@ export const Gantt = ({ limit, runType, triggeringUser }:
Props) => {
if (taskInstance) {
const hasTaskRunning = isStatePending(taskInstance.state);
- const endTime = hasTaskRunning ? currentTime :
taskInstance.end_date;
+ const endTime = hasTaskRunning ? dayjs().toISOString() :
taskInstance.end_date;
return {
isGroup: node.isGroup,
isMapped: node.is_mapped,
state: taskInstance.state,
taskId: taskInstance.task_id,
- x: [
- formatDate(taskInstance.start_date, selectedTimezone,
DEFAULT_DATETIME_FORMAT_WITH_TZ),
- formatDate(endTime, selectedTimezone,
DEFAULT_DATETIME_FORMAT_WITH_TZ),
- ],
+ x: [dayjs(taskInstance.start_date).toISOString(),
dayjs(endTime).toISOString()],
y: taskInstance.task_id,
};
}
@@ -196,7 +190,7 @@ export const Gantt = ({ limit, runType, triggeringUser }:
Props) => {
return undefined;
})
.filter((item) => item !== undefined);
- }, [flatNodes, gridTiSummaries, taskInstancesData, selectedTimezone,
isLoading, runId, currentTime]);
+ }, [flatNodes, gridTiSummaries, taskInstancesData, isLoading, runId]);
// Get all unique states and their colors
const states = [...new Set(data.map((item) => item.state ?? "none"))];