mui / mui-x

MUI X: Build complex and data-rich applications using a growing list of advanced React components, like the Data Grid, Date and Time Pickers, Charts, and more!
https://mui.com/x/
4.11k stars 1.27k forks source link

[pickers] `DateCalendar` shows duplicate dates for DST when using `AdapterMoment` #14730

Open gurtajkhatra opened 3 days ago

gurtajkhatra commented 3 days ago

Steps to reproduce

Link to live example: https://codesandbox.io/p/sandbox/y6cws5

Steps:

  1. Scroll to October with the timezone set to America/Asuncion on the StaticDatePicker
  2. October 5th is shown twice in the calendar and every day in October after that is shifted by a day (Ex Oct 8th is shown as a Wednesday, but it should be a Tuesday

CleanShot 2024-09-25 at 12 23 33

Current behavior

October 5th is shown twice in the StaticDatePicker for the America/Asuncion timezone causing all dates to be shifted by a day

Expected behavior

October 5th should only be shown on Saturday.

Context

No response

Your environment

See the code sandbox here: https://codesandbox.io/p/sandbox/y6cws5

Search keywords: daylight savings DST

flaviendelangle commented 1 day ago

Your example only seems to be broken with Moment, with Day.js it seems to work fine. I found a very similar comment in an issue of the moment repo: https://github.com/moment/moment/issues/4743#issuecomment-422567232

This code snippet seems to work, but it's not the kind of thing I'm very happy to introduce in the codebase :cry:

Here is the diff:

diff --git a/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts b/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts
index a6e5288f2..f49bcc678 100644
--- a/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts
+++ b/packages/x-date-pickers/src/AdapterMoment/AdapterMoment.ts
@@ -528,7 +528,17 @@ export class AdapterMoment implements MuiPickersAdapter<Moment, string> {
       nestedWeeks[weekNumber] = nestedWeeks[weekNumber] || [];
       nestedWeeks[weekNumber].push(current);

+      const prev = current;
       current = this.addDays(current, 1);
+
+      // If there is a TZ change at midnight, adding 1 day may only increase the date by 23 hours to 11pm
+      // To fix, bump the date into the next day (add 12 hours) and then revert to the start of the day
+      // See https://github.com/moment/moment/issues/4743#issuecomment-811306874 for context.
+      const diff = current.diff(prev, 'hours');
+      if (diff === 23 && prev.get('h') === 0) {
+        current = current.add(12, 'h').startOf('day');
+      }
+
       count += 1;
     }

I'm adding it to our board for grooming :+1: