Will_71
September 13, 2026, 1:55pm
1
I think I have an issue with the calendar display
In October, I have the 25th twice, a Sunday and a Monday.
In the weekly view, the day goes from 10 p.m. to 9 p.m.
Same in the daily view
Have other people noticed these issues?
prohand
September 13, 2026, 2:16pm
2
Hello,
I actually have the same bugs and itβs not just in October
Will_71
September 13, 2026, 7:45pm
3
bug on Mars 2027 where the grayed-out days at the end of the month are incorrect.
So Iβm going to open a PR to fix all these points
Will_71
September 13, 2026, 8:40pm
4
I dug into this bug, and there are actually three distinct symptoms sharing a single cause.
The cause
The front end uses dayjs for all date calculations. A dashboard box (EDF Tempo) loaded the timezone plugin of dayjs to read the time in Paris.
The problem: dayjs.extend() globally modifies dayjs for the entire application. And the calendar library (react-big-calendar) contains this test:
// if the timezone plugin is loaded, then use the timezone aware version
const dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
As soon as the plugin is present, the calendar switches all its calculations to dayjs.tz, which behaves differently:
it interprets certain dates as UTC β the time grid shifts by 2 hours
add(1, βΉ jour βΊ) adds 24 absolute hours, whereas the day of the winter time change lasts 25 hours β we fall back to 23:00 on the same day, hence the date displayed twice
startOf(βΉ mois βΊ) shifts by one hour, which distorts the comparison of months β the greying inverts
Important point: this box was statically imported with all the others, so the plugin was loaded even if you never used EDF Tempo.
The fix
Instead of patching the calendar, I removed the cause: the EDF Tempo box now uses Intl.DateTimeFormat (native, without side effects) to read the time in Paris. The business behavior is identical β the full/off-peak hours remain defined in French time regardless of your time zone.
There remains a fix in the calendar, for a bug independent of this one: the day of the time change displayed 26 time slots in October and 22 in March instead of 24, and the events were mispositioned (an appointment at 14:00 was displayed at 13:26).
The PR:
master β William-De71:fix/calendar-dayjs-timezone-plugin
ouvert 08:40PM - 13 Sep 26 UTC
Description :
## The problem
Three calendar display bugs reported on the f⦠orum, all sharing one root cause:
1. In week and day views, the time gutter started at 22:00 instead of 00:00 β
shifted by the local UTC offset
2. In month view, a date appeared twice around the October DST switch (the
"25th shown twice, on the Sunday and on the Monday")
3. In month view, the last days of the month were greyed as out-of-range while
the first days of the next month looked in-range
## The root cause
The EDF Tempo box loaded dayjs's `timezone` plugin to read the Paris hour.
`dayjs.extend()` mutates the shared dayjs singleton, and react-big-calendar
switches its whole date arithmetic over to `dayjs.tz` as soon as the plugin is
present:
```js
// react-big-calendar/lib/localizers/dayjs.js
const dayjs = dayjsLib.tz ? dayjsLib.tz : dayjsLib;
dayjs.tz then behaves differently on three paths:
ββββββββββββββββββββββββββββββββ¬βββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Call β Without the plugin β With the plugin β
ββββββββββββββββββββββββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β merge(date, min) β 00:00 local β 22:00 the day before (string reparsed as UTC) β
ββββββββββββββββββββββββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β add(25 Oct, 1 day) β 26 Oct 00:00 β 25 Oct 23:00 (24 absolute hours, but that day lasts 25) β
ββββββββββββββββββββββββββββββββΌβββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β startOf('month') on 30 March β 28 Feb 23:00 β 28 Feb 22:00 (an hour off past the DST switch) β
ββββββββββββββββββββββββββββββββ΄βββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
```
Each one maps to one of the symptoms above: the shifted gutter, the duplicated
day, and the inverted greying.
The box is imported statically in Box.jsx along with every other dashboard
box, so the plugin loaded for everyone β including users who never used EDF
Tempo. That is why the bug looked unrelated to it on the forum.
The fix
Rather than patching the calendar around each symptom, this removes the cause:
EDF Tempo now reads the Paris hour with Intl.DateTimeFormat, which is native
and has no global side effect. The business behaviour is unchanged β Tempo peak
hours stay defined in French local time whatever timezone the browser sits in
(verified against dayjs.tz from a non-Paris timezone, on winter midnight,
summer midnight and midday: identical values).
An ESLint rule blocks the plugin import so this cannot silently come back.
Also fixes an unrelated react-big-calendar bug the DST day exposed: the day and
week views size their grid from getTotalMin(), which returns elapsed minutes
(1500 in autumn, 1380 in spring), while event placement already folds the shift
away and works on a 1440 minute scale. The grid got 25 rows in October and 23 in
March, and a 2pm event rendered at 1:26pm on the October change.
Testing
Verified without the plugin across Europe/Paris, America/New_York,
Australia/Sydney, Pacific/Auckland, America/Santiago and UTC:
- time gutter starts at 00:00 with 24 rows, every day of 2026
- month view 2024-2030: no duplicated day, greying matches the displayed month
One expected exception: in America/Santiago on 6 September 2026 the gutter
starts at 01:00 with 23 rows β midnight does not exist there that day, the clock
jumps from 23:59 to 01:00. That is correct behaviour.
Fixes the bugs reported at
https://community.gladysassistant.com/t/bug-affichage-calendrier/10857
### Checklist
- [X] If a forum topic or GitHub issue exists, the description links it (`Forum: https://community.gladysassistant.com/t/...` or `Closes #...`)
- [X] Tests pass: `cd server && npm run coverage` (Codecov requires 100% coverage on changed lines) and Cypress (`npm run cypress:run`) if the UI changed
- [X] Linter and prettier pass on both front and server (`npm run eslint`, `npm run prettier`)
- [X] No undocumented breaking change
π€ Generated with Claude Code