Skip to content

[OPE-165] Fix holiday dates shifting timezone#103

Merged
singret merged 4 commits into
mainfrom
ope-165-holiday-timezone
May 26, 2026
Merged

[OPE-165] Fix holiday dates shifting timezone#103
singret merged 4 commits into
mainfrom
ope-165-holiday-timezone

Conversation

@singret
Copy link
Copy Markdown
Contributor

@singret singret commented May 26, 2026

Summary

  • Introduces models.DateOnly (named string type) — stores and marshals holiday dates as "YYYY-MM-DD" with no timezone component, eliminating accidental RFC3339 timestamp serialization
  • Changes ScheduleHoliday.Date from time.Time to DateOnly; DB column was already DATE — no migration needed
  • Fixes ScheduleDetailPage to use local timezone date strings (localDateStr) instead of toISOString().slice(0,10) for:
    • Holiday API from/to params (UTC caused UTC+ users to miss last-day-of-month holidays)
    • Today's holiday badge todayStr
    • Unavailability past/active status comparison

Root cause

toISOString() always returns the UTC date. For UTC+5:30 users, the window end computed as toISOString().slice(0,10) was one calendar day earlier than the visible month end, causing the last day's holidays to not load. The todayStr mismatch caused the today's holiday banner to be off by ±1 day depending on timezone offset.

Test plan

  • Run go test ./... — all pass
  • npm run build — zero errors
  • View schedule with Indian holidays in IST: confirm holidays appear on the correct calendar day
  • Verify UTC+0 and UTC-5 are also correct (no regression)
  • Last day of month (e.g. May 31 holiday) visible for UTC+ users

singret added 4 commits May 26, 2026 10:35
ScheduleUnavailability.StartDate/EndDate now use DateOnly (same as
holidays) so the evaluator never misinterprets a stored date as a UTC
midnight timestamp.

buildUnavailableSet and collectBoundaries now accept a *time.Location
derived from schedule.Timezone.  Unavailability boundaries are computed
as midnight-in-schedule-tz rather than UTC midnight, so a leave marked
for DATE 2026-05-28 in Asia/Kolkata is excluded exactly on IST May 28
instead of bleeding into May 29.

Also changes onSaved for the unavailability modal to call invalidateAll()
(which also bumps the Gantt timeline key) instead of refetch() alone,
so the Gantt chart updates immediately without a manual page refresh.
Segment ends are exclusive (end = start of next segment). Using >= was
harmless before because UTC-aligned boundaries never exactly coincided
with local midnight. Now that collectBoundaries uses schedule-timezone
midnight, the boundary is exactly at the local day start and the >=
comparison incorrectly matched the next day.
@singret singret merged commit a6c1c0d into main May 26, 2026
4 of 8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant