MUI DateCalendar 与 Luxon 适配器从周日开始一周

Mr.*_*yyy 7 luxon mui-x mui-x-date-picker

最近,Luxon 增加了对本地化周信息的支持。我将 Luxon 版本更新到包含此更新的最新版本,3.4.4但打开日历时,一周仍然从星期一开始,而不是星期日。

我认为LuxonAdapter会接受更改并使用本地化的周数据,但它似乎没有任何不同。

package.json有两个库的最新版本:

"@mui/x-date-pickers": "^7.0.0-alpha.0",
"luxon": "^3.4.4",
Run Code Online (Sandbox Code Playgroud)

然后,在我的中App.tsx添加LocalizationProviderLuxonAdapter

import { LocalizationProvider } from "@mui/x-date-pickers";
import { AdapterLuxon } from "@mui/x-date-pickers/AdapterLuxon";

<LocalizationProvider dateAdapter={AdapterLuxon}>
    <Outlet />
</LocalizationProvider>
Run Code Online (Sandbox Code Playgroud)

最后,DateCalendar组件:

import { DateTime } from "luxon";
import { DateCalendar } from "@mui/x-date-pickers";

const [calendarValue, setCalendarValue] = useState<DateTime | null>(DateTime.now());

<DateCalendar
    value={calendarValue}
    onChange={setCalendarValue}
    views={["day"]}
    disablePast
    sx={{ m: 0 }}
/>
Run Code Online (Sandbox Code Playgroud)

Von*_*onC 3

我看到你目前有:

\n
Client Application\n\xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80 package.json\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 "@mui/x-date-pickers": "^7.0.0-alpha.0"\n\xe2\x94\x82  \xe2\x94\x94\xe2\x94\x80 "luxon": "^3.4.4"\n\xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80 App.tsx\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 LocalizationProvider (with LuxonAdapter)\n\xe2\x94\x82  \xe2\x94\x94\xe2\x94\x80 Outlet\n\xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80 DateCalendar Component\n   \xe2\x94\x9c\xe2\x94\x80 DateTime from "luxon"\n   \xe2\x94\x94\xe2\x94\x80 DateCalendar from "@mui/x-date-pickers"\n
Run Code Online (Sandbox Code Playgroud)\n

首先验证Luxon是否配置了从周日开始一周的正确区域设置。如果您的区域设置设置为传统上一周从星期一开始,Luxon 将遵循该设置。

\n
Client Application\n\xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80 package.json\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 "@mui/x-date-pickers": "^7.0.0-alpha.0"\n\xe2\x94\x82  \xe2\x94\x94\xe2\x94\x80 "luxon": "^3.4.4"\n\xe2\x94\x82\n\xe2\x94\x9c\xe2\x94\x80 App.tsx\n\xe2\x94\x82  \xe2\x94\x9c\xe2\x94\x80 LocalizationProvider (with LuxonAdapter)\n\xe2\x94\x82  \xe2\x94\x94\xe2\x94\x80 Outlet\n\xe2\x94\x82\n\xe2\x94\x94\xe2\x94\x80 DateCalendar Component\n   \xe2\x94\x9c\xe2\x94\x80 DateTime from "luxon"\n   \xe2\x94\x94\xe2\x94\x80 DateCalendar from "@mui/x-date-pickers"\n
Run Code Online (Sandbox Code Playgroud)\n

如果 LuxonAdapter 没有自动从 Luxon 设置中选择一周的开始,您可能需要显式配置它。但我没有看到直接执行此操作的方法@mui/x-date-pickers

\n

mui/material-ui问题 30591建议,关于moment/luxon问题 1447引用的类似问题(正是您的moment/luxonPR 1454

\n
import { Settings } from \'luxon\';\n\n// Set the locale globally for Luxon\nSettings.defaultLocale = \'your-locale\'; // Replace \'your-locale\' with the appropriate locale code\n
Run Code Online (Sandbox Code Playgroud)\n

自定义适配器工厂函数adapterLuxonFactory采用一个weekStartsOn参数(代表一周开始日期的数字,其中1表示星期一,2表示星期二,最多7表示星期日)。该函数用于LocalizationProvider确保整个日历组件遵循指定的一周开始时间。

\n

要将此解决方案集成到您当前的设置中,您可以通过LuxonAdapter修改以使用此自定义适配器来替换此自定义适配器的标准以进行测试。\n请确保在初始化适配器时提供正确的值。对于从周日开始一周,这将是LocalizationProviderApp.tsx
weekStartsOn7

\n
\n

我还看到了mui/mui-x问题 9984,其中说:

\n
\n

自 2021 年以来,我一直在使用mui/material-ui-pickers问题 1270中提到的解决方法中提到的解决方法来强制 Luxon 使用星期日作为一周的第一天,但​​发现它不再有效。

\n
function adapterLuxonFactory(weekStartsOn: number) {\n  class Adapter extends AdapterLuxon {\n    private weekStartsOn = weekStartsOn;\n\n    /** Controls the header of the calendar month view. */\n    public getWeekdays = () => {\n      const weekdays = Info.weekdaysFormat("narrow", { locale: this.locale });\n      const start = weekdays.slice(0, this.weekStartsOn - 1);\n      const end = weekdays.slice(this.weekStartsOn - 1);\n      return [...end, ...start];\n    };\n\n    /** Controls the day buttons of the calendar month view. */\n    getWeekArray = (date: DateTime) => {\n      const startOfMonth = date.startOf("month");\n      const endOfMonth = date.endOf("month");\n      const firstDayOfMonth = startOfMonth.weekday;\n\n      const startOfWeek = startOfMonth.minus({\n        days: (firstDayOfMonth - this.weekStartsOn + 7) % 7,\n      });\n\n      const endOfWeek = endOfMonth\n        .plus({ days: 6 - endOfMonth.weekday + this.weekStartsOn })\n        .endOf("day");\n\n      const { days } = endOfWeek.diff(startOfWeek, "days").toObject();\n\n      const weeks: DateTime[][] = [];\n      new Array<number>(Math.round(days ?? 0))\n        .fill(0)\n        .map((_, i) => i)\n        .map((day) => startOfWeek.plus({ days: day }))\n        .forEach((v, i) => {\n          if (i === 0 || (i % 7 === 0 && i > 6)) {\n            weeks.push([v]);\n            return;\n          }\n\n          weeks[weeks.length - 1].push(v);\n        });\n\n      return weeks;\n    };\n  }\n\n  return Adapter;\n}\n\nexport function LocalizationProvider({\n  children,\n}: {\n  children?: React.ReactNode;\n}): JSX.Element {\n  const { weekStartsOn } = useYourOwnDatabase();\n\n  return (\n    <MuiLocalizationProvider dateAdapter={adapterLuxonFactory(weekStartsOn)}>\n      {children}\n    </MuiLocalizationProvider>\n  );\n}\n
Run Code Online (Sandbox Code Playgroud)\n

我可以通过添加 startOfWeek 方法的覆盖来修复它,如下所示:

\n
import {Info} from \'luxon\';\nimport LuxonUtils from \'@date-io/luxon\';\n\nclass CustomLuxonUtils extends LuxonUtils {\n  getWeekdays() {\n    // need to copy the existing, and use Info to preserve localization\n    const days = [...Info.weekdaysFormat(\'narrow\', this.locale)];\n    // remove Sun from end of list and move to start of list\n    days.unshift(days.pop());\n    return days;\n  }\n\n  getWeekArray(date) {\n    const endDate = date\n      .endOf(\'month\')\n      // if a month ends on sunday, luxon will consider it already the end of the week\n      // but we need to get the _entire_ next week to properly lay that out\n      // so we add one more day to cover that before getting the end of the week\n      .plus({days: 1})\n      .endOf(\'week\');\n    const startDate = date\n      .startOf(\'month\')\n      .startOf(\'week\')\n      // must subtract 1, because startOf(\'week\') will be Mon, but we want weeks to start on Sun\n      // this is the basis for every day in a our calendar\n      .minus({days: 1});\n\n    const {days} = endDate.diff(startDate, \'days\').toObject();\n\n    const weeks = [];\n    new Array(Math.round(days))\n      .fill(0)\n      .map((_, i) => i)\n      .map(day => startDate.plus({days: day}))\n      .forEach((v, i) => {\n        if (i === 0 || (i % 7 === 0 && i > 6)) {\n          weeks.push([v]);\n          return;\n        }\n\n        weeks[weeks.length - 1].push(v);\n      });\n\n    // a consequence of all this shifting back/forth 1 day is that you might end up with a week\n    // where all the days are actually in the previous or next month.\n    // this happens when the first day of the month is Sunday (Dec 2019 or Mar 2020 are examples)\n    // or the last day of the month is Sunday (May 2020 or Jan 2021 is one example)\n    // so we\'re only including weeks where ANY day is in the correct month to handle that\n    return weeks.filter(w => w.some(d => d.month === date.month));\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

这在mui/mui-x问题 10805中进行了讨论:“[pickers]支持在 AdapterLuxon 上更改工作日的开始”

\n
\n

干净的修复将合并到 v7 alpha 分支中。

\n
\n

这是mui/mui-xPR 10964

\n