Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DatePicker AdapterLuxon start day of the week with Sunday #12821

Closed
1 task done
georgesglynn opened this issue Jan 12, 2022 · 13 comments
Closed
1 task done

DatePicker AdapterLuxon start day of the week with Sunday #12821

georgesglynn opened this issue Jan 12, 2022 · 13 comments
Labels
bug 🐛 Something doesn't work component: date picker This is the name of the generic UI component, not the React module! duplicate This issue or pull request already exists

Comments

@georgesglynn
Copy link

georgesglynn commented Jan 12, 2022

Duplicates

  • I have searched the existing issues

Summary 💡

Hello! I am a dev at Southwest Airlines and we have absolutely LOVED using the MUI package for our team's application.

We are currently on V4, I am working towards getting us upgraded to V5. This particular issue has been around for us since early last year but now that the DatePicker is under the lab package and I am currently working on migrating our implementation with https://material-ui-pickers.dev/ to the lab package I figure this would be a good time to bring this up.

Today, if you use the DatePicker component with the AdapterLuxon component as the LocalizationProvider, the week by default starts with Monday.

I tried to look into the AdapterLuxon code myself to see if I could customize it directly for our use case but I could not figure it out. Any guidance on this would be greatly appreciated!

Examples 🌈

Screenshots for clarity:
(AdapterLuxon)
image

(AdapterDateFns)
image

Motivation 🔦

Our customers require this calendar to start with Sunday, but this component provides no customization to change this. That is my feature request, to add a prop to the DatePicker component that would allow you to change the starting day of the week.

Today since we primarily use Luxon, we have to convert every Luxon date that interacts with this DatePicker component to DateFns and use the AdapterDateFns in order to have the calendar start each week with Sunday. It is a lot of overhead/messy work.

Search keywords:

@georgesglynn georgesglynn added the status: waiting for maintainer These issues haven't been looked at yet by a maintainer label Jan 12, 2022
@Blackburn29
Copy link

I have this same problem for an application I am working on. This appears to be an issue with how Luxon reports the days of week using Intl. The issue can be reproduced by calling the date adapter function getWeekdays() which fetches the days of week.

https://github.com/dmtrKovalenko/date-io/blob/master/packages/luxon/src/luxon-utils.ts#L332

luxon.Info.weekdaysFormat("narrow", { locale: 'en' });
(7) ['M', 'T', 'W', 'T', 'F', 'S', 'S']

@michaldudak michaldudak added bug 🐛 Something doesn't work component: date picker This is the name of the generic UI component, not the React module! and removed status: waiting for maintainer These issues haven't been looked at yet by a maintainer labels Jan 14, 2022
@sam-woodridge
Copy link

Any updates on this??

@patrickclancy
Copy link

patrickclancy commented Jan 10, 2023

We have the same issue with Material UI and AdapterLuxon. I'd like to continue to use Luxon, but without being able to set the start of the week to Sunday. We'll have to abandon Luxon for another package. We get a ton of user complaints about the date picker's calendar layout.

@sam-woodridge
Copy link

@patrickclancy you can override the dateAdapter it uses so that it starts weeks on Sunday. I adapted the following from mui/material-ui-pickers#1270 (comment):

import React, { PropsWithChildren } from 'react';
import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
import { DateTime } from 'luxon';
import { LocalizationProvider } from '@mui/x-date-pickers';

class Adapter extends AdapterLuxon {
    public getWeekdays = () => {
        return ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
    };

    getWeekArray = (date: DateTime) => {
        const { days } = date
            .endOf('month')
            .endOf('week')
            .diff(date.startOf('month').startOf('week'), 'days')
            .toObject();

        let weeks: DateTime[][] = [];
        new Array(Math.round(days ?? 0))
            .fill(0)
            .map((_, i) => i)
            .map(day =>
                date
                    .startOf('month')
                    .startOf('week')
                    .minus({ days: 1 })
                    .plus({ days: day }),
            )
            .forEach((v, i) => {
                if (i === 0 || (i % 7 === 0 && i > 6)) {
                    weeks.push([v]);
                    return;
                }

                weeks[weeks.length - 1].push(v);
            });

        weeks = weeks.filter(week => {
            // do not allow weeks with start or end outside of current month
            return (
                week[0].hasSame(date, 'month') ||
                week[week.length - 1].hasSame(date, 'month')
            );
        });

        return weeks;
    };
}

export const DatePickerProvider: React.FC<PropsWithChildren> = ({
    children,
}) => (
    <LocalizationProvider dateAdapter={Adapter}>
        {children}
    </LocalizationProvider>
);

Then you can just wrap your app with DatePickerProvider and it should work.

@flaviendelangle
Copy link
Member

Concerning luxon, it seems to be a limitation of the library itself (moment/luxon#373).

@adwher
Copy link

adwher commented Sep 18, 2023

Until Luxon supports the change of the start-week day, I'm want to share the solution that works for me even with five-weeks months cases:

import AdapterLuxon from '@mui/lab/AdapterLuxon';
import { DateTime } from 'luxon';

const DAYS_ON_WEEK = 7;

/**
 * Luxon adapter for the `LocalizationProvider` component to set the sunday as first day of the week.
 */
export class CustomLuxonAdapter extends AdapterLuxon {
  /** Set the order of the labels in a week. */
  getWeekdays = () => {
    return ['S', 'M', 'T', 'W', 'T', 'F', 'S'];
  };

  /** Generate the dates per month. */
  getWeekArray = (initial: DateTime) => {
    const monthStart = initial.startOf('month').startOf('week');
    const monthEnd = initial.endOf('month').endOf('week');
    const range = monthStart.diff(monthEnd);

    const weeks = Math.round(Math.abs(range.as('weeks'))) + 1;
    const days = weeks * DAYS_ON_WEEK;

    const month: DateTime[][] = [];

    for (let index = 0; index < days; index++) {
      const week = month.length - 1;

      const date = initial
        .startOf('month')
        .startOf('week')
        .plus({ day: index - 1 });

      if (index === 0 || index % 7 === 0) {
        month.push([date]);
        continue;
      }

      month[week] = [...month[week], date];
    }

    return month;
  };
}

Thanks @sam-woodridge for the codebase.

@svey
Copy link

svey commented Sep 29, 2023

My team has this issue too, implementing @sam-woodridge 's solution (thank you!) However, this is almost table-stakes for us. It would be great to get this handled

@NealEhardt
Copy link

NealEhardt commented Oct 11, 2023

Here's a date adapter that accepts any day (1-7) as the start-of-week. The factory pattern allows us to change the start-of-week mid-session, when the user selects a different locale.

function adapterLuxonFactory(weekStartsOn: number) {
  class Adapter extends AdapterLuxon {
    private weekStartsOn = weekStartsOn;

    /** Controls the header of the calendar month view. */
    public getWeekdays = () => {
      const weekdays = Info.weekdaysFormat("narrow", { locale: this.locale });
      const start = weekdays.slice(0, this.weekStartsOn - 1);
      const end = weekdays.slice(this.weekStartsOn - 1);
      return [...end, ...start];
    };

    /** Controls the day buttons of the calendar month view. */
    getWeekArray = (date: DateTime) => {
      const startOfMonth = date.startOf("month");
      const endOfMonth = date.endOf("month");
      const firstDayOfMonth = startOfMonth.weekday;

      const startOfWeek = startOfMonth.minus({
        days: (firstDayOfMonth - this.weekStartsOn + 7) % 7,
      });

      const endOfWeek = endOfMonth
        .plus({ days: 6 - endOfMonth.weekday + this.weekStartsOn })
        .endOf("day");

      const { days } = endOfWeek.diff(startOfWeek, "days").toObject();

      const weeks: DateTime[][] = [];
      new Array<number>(Math.round(days ?? 0))
        .fill(0)
        .map((_, i) => i)
        .map((day) => startOfWeek.plus({ days: day }))
        .forEach((v, i) => {
          if (i === 0 || (i % 7 === 0 && i > 6)) {
            weeks.push([v]);
            return;
          }

          weeks[weeks.length - 1].push(v);
        });

      return weeks;
    };
  }

  return Adapter;
}

export function LocalizationProvider({
  children,
}: {
  children?: React.ReactNode;
}): JSX.Element {
  const { weekStartsOn } = useYourOwnDatabase();

  return (
    <MuiLocalizationProvider dateAdapter={adapterLuxonFactory(weekStartsOn)}>
      {children}
    </MuiLocalizationProvider>
  );
}

This is built on @sam-woodridge 's solution.

@flaviendelangle
Copy link
Member

Thanks for your solution!

I would just advise you to memoize the adapter because it is used in a lot of memoization processed inside the pickers.

@Lori-Becker
Copy link

In case anyone stumbles upon this thread again, you can now set the first day of the week with Luxon. This code is straight from MUI's documentation:

import { Settings, Info } from 'luxon';

Settings.defaultWeekSettings = {
  // Sunday = 7, Monday = 1.
  firstDay: 1,
  // Makes sure we don't lose the other information from `defaultWeekSettings`
  minimalDays: Info.getMinimumDaysInFirstWeek(),
  weekend: Info.getWeekendWeekdays(),
};

Place this somewhere near the top of your React application (I put it in App.tsx). I set the firstDay to 7 (Sunday) and now all my MUI date pickers are displaying Sunday as the first day of the week.

@ZeeshanTamboli ZeeshanTamboli transferred this issue from mui/material-ui Apr 17, 2024
@ZeeshanTamboli
Copy link
Member

@flaviendelangle I've moved the issue to the MUI X repository. Could you verify if it's still relevant?

@LukasTy
Copy link
Member

LukasTy commented Apr 18, 2024

Closing as a duplicate of #10805, which is already resolved with #10964 and is released starting from v7.0.0-alpha.3.

@LukasTy LukasTy closed this as not planned Won't fix, can't repro, duplicate, stale Apr 18, 2024
@LukasTy LukasTy added the duplicate This issue or pull request already exists label Apr 18, 2024
Copy link

⚠️ This issue has been closed. If you have a similar problem but not exactly the same, please open a new issue.
Now, if you have additional information related to this issue or things that could help future readers, feel free to leave a comment.

@georgesglynn: How did we do? Your experience with our support team matters to us. If you have a moment, please share your thoughts in this short Support Satisfaction survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 Something doesn't work component: date picker This is the name of the generic UI component, not the React module! duplicate This issue or pull request already exists
Projects
None yet
Development

No branches or pull requests