pyzo-ryzo opened a new issue, #67477:
URL: https://github.com/apache/airflow/issues/67477
### Under which category would you file this issue?
Airflow Core
### Apache Airflow version
3.2.1
### What happened and how to reproduce it?
The Calendar view on the DAG detail page does not respect the user's
selected timezone from the UI timezone selector. All dates — both in the API
query parameters and in the rendered calendar grid — are computed using either
browser-local time or hardcoded UTC, while the rest of the UI (e.g. the "Start
Date" column on the Runs tab) correctly converts timestamps to the
user-selected timezone.
**Observed behavior:** Changing the timezone via the UI timezone selector
has no effect on the Calendar view. Runs are grouped into the wrong day/hour
cells for users whose selected timezone differs from UTC.
**Comparison with Runs tab:** On the Runs tab, the `Start Date` column
properly updates when the user changes their timezone setting, confirming the
timezone selector itself works correctly.
## How to reproduce
1. Set your Airflow UI timezone to something significantly offset from UTC
(e.g. `Asia/Tokyo` — UTC+9, or `America/Los_Angeles` — UTC-7).
2. Navigate to a DAG that has runs near midnight UTC.
3. Open the **Calendar** tab → observe that runs are grouped by their UTC
date/hour, not by the selected timezone.
4. Switch to the **Runs** tab → observe that the `Start Date` column
correctly shows times in the selected timezone.
## Root cause analysis
The entire Calendar feature tree (`Calendar.tsx`, `calendarUtils.ts`,
`HourlyCalendarView.tsx`, `DailyCalendarView.tsx`) was written using plain
`dayjs()` without any awareness of the `useTimezone()` / `TimezoneContext`
system that the rest of the Airflow UI uses. The `dayjs/plugin/timezone` and
`dayjs/plugin/utc` plugins are not even imported in any of these files.
There are three specific problem areas:
### 1. `Calendar.tsx` — API query dates hardcode a literal "Z" suffix
```typescript
// Current code (Calendar.tsx)
const gte = startDate.format("YYYY-MM-DD[T]HH:mm:ss[Z]");
const lte = endDate.format("YYYY-MM-DD[T]HH:mm:ss[Z]");
```
`[Z]` in a dayjs format string is a **literal character escape** — it
unconditionally appends the letter `Z` (meaning "UTC") to whatever the
browser-local time value is. This tells the API the timestamp is UTC when it is
not. The component never calls `useTimezone()`.
Compare with the `Time` component (used by the Runs tab), which correctly
does:
```typescript
// Time.tsx — correct pattern
const { selectedTimezone } = useTimezone();
const formattedTime = time.tz(selectedTimezone).format(format);
```
### 2. `calendarUtils.ts` — Run grouping uses raw UTC string slicing
```typescript
// createDailyDataMap
const dateStr = run.date.slice(0, 10); // "YYYY-MM-DD" — always UTC
// createHourlyDataMap
const hourStr = run.date.slice(0, 13); // "YYYY-MM-DDTHH" — always UTC
```
If the API returns a UTC timestamp like `2024-01-15T23:30:00Z`, this groups
the run into January 15. But for a user in `Asia/Tokyo` (UTC+9), that run
occurred on January 16 at 08:30 and should appear in that day's cell.
The `generateDailyCalendarData` and `generateHourlyCalendarData` functions
also build their calendar grids using plain `dayjs()` (browser-local), with no
timezone parameter.
### 3. `HourlyCalendarView.tsx` / `DailyCalendarView.tsx` — Display
formatting uses plain dayjs
Both views format display labels (day number, weekday name, month
abbreviation) with plain `dayjs(day.day)` calls that don't go through timezone
conversion.
## Suggested fix
Thread `selectedTimezone` from the `useTimezone()` hook through the
component tree:
- **`Calendar.tsx`**: Import `useTimezone`, compute the date range in the
selected timezone, convert to UTC for the API query.
- **`calendarUtils.ts`**: Add a `timezone` parameter to
`createDailyDataMap`, `createHourlyDataMap`, `generateDailyCalendarData`,
`generateHourlyCalendarData`, and `calculateDataBounds`. Use
`dayjs(run.date).tz(timezone)` instead of string slicing for grouping.
- **Views**: Pass the timezone through and use it for display formatting.
This follows the same pattern already established by
`src/components/Time.tsx` and `src/utils/datetimeUtils.ts`.
### Affected files
- `airflow-core/src/airflow/ui/src/pages/Dag/Calendar/Calendar.tsx`
- `airflow-core/src/airflow/ui/src/pages/Dag/Calendar/calendarUtils.ts`
- `airflow-core/src/airflow/ui/src/pages/Dag/Calendar/HourlyCalendarView.tsx`
- `airflow-core/src/airflow/ui/src/pages/Dag/Calendar/DailyCalendarView.tsx`
### What you think should happen instead?
The Calendar view should respect the user-selected timezone (from
`useTimezone()` / `TimezoneContext`) consistently with the rest of the UI.
Specifically:
1. The date range sent to the API should be computed in the selected
timezone and then converted to UTC.
2. Runs should be grouped into day/hour buckets based on the selected
timezone, not by raw UTC string slicing.
3. Display labels (day numbers, weekday names, month headers) should reflect
the selected timezone.
### Operating System
Red Hat Enterprise Linux 9.7
### Deployment
Virtualenv installation
### Apache Airflow Provider(s)
_No response_
### Versions of Apache Airflow Providers
_No response_
### Official Helm Chart version
Not Applicable
### Kubernetes Version
Not Applicable
### Helm Chart configuration
Not Applicable
### Docker Image customizations
_No response_
### Anything else?
The `CalendarCell.tsx` tooltip display may also need updating if it shows
raw date strings, but the four files listed above are the core of the issue.
### Are you willing to submit PR?
- [x] Yes I am willing to submit a PR!
### Code of Conduct
- [x] I agree to follow this project's [Code of
Conduct](https://github.com/apache/airflow/blob/main/CODE_OF_CONDUCT.md)
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]