远程时区的material-ui LocalizationProvider
Posted
技术标签:
【中文标题】远程时区的material-ui LocalizationProvider【英文标题】:material-ui LocalizationProvider for a remote time zone 【发布时间】:2021-06-16 05:39:39 【问题描述】:我的应用需要 material-ui 日期和时间选择器来在服务器指定的远程时区上运行。我希望日期选择器上的今天圆圈实际指示远程时区的今天,并且我想将远程时区中的日期时间转换为自 1970-01-01T00:00:00Z
以来的秒数。
我正在使用 material-ui v5 alphas。 docs 表示您为时间库指定了 @date-io
adapter。看起来有四个明显的选择:
@date-io/date-fns
(基于 date-fns 和 date-fns-tz 有一个损坏的远程时区设计。它使用 javascript 日期来表示远程时区中的日期和时间,但如果本地时区有一个“春天”小时,有些时候你无法代表。issue。
@date-io/dayjs
(基于dayjs)不能正确处理夏令时。 issue
@date-io/luxon
(基于 luxon)看起来很有希望
@date-io/moment
(基于 moment 和 moment-timezone)看起来很有希望
所以我想为 luxon 或 moment 指定一个在特定区域中构造日期的适配器。
这两个库都支持设置全局默认时区(luxon、moment),但我更喜欢在构建特定日期适配器时设置时区。根据服务器响应混淆全局状态是很严重的。
我找到了一个date-io issue,上面写着:
您可以将时刻时区直接传递给
libInstance
,在这种情况下,它将使用时刻实例或全局时区集
这就是我想要的!但我对这个实例到底应该是什么感到困惑。我对 Javascript 还很陌生,这对我没有帮助。
@date-io/luxon
构造函数现在似乎不允许像这样覆盖实例。
试图让这一刻开始工作:
$ mkdir tztest
$ cd tztest
$ npm init -y
$ npm install --save moment moment-timezone '@date-io/moment'
$ node
> let MomentUtils = require('@date-io/moment');
undefined
> let moment = require('moment');
undefined
> let _ = require('moment-timezone');
undefined
> // Operations including the following should all work similarly to when using the default instance:
> (new MomentUtils()).date();
Moment<2021-03-18T11:57:30-07:00>
> (new MomentUtils()).date('2021-01-01T00:00:00');
Moment<2021-01-01T00:00:00-08:00>
> (new MomentUtils()).getCurrentLocaleCode();
'en'
> // Here's some garbage I tried
> (new MomentUtils(instance: moment().tz('America/New_York'))).date();
Uncaught TypeError: _this.moment is not a function
at MomentUtils.date (/Users/slamb/git/tztest/node_modules/@date-io/moment/build/index.js:78:32)
> (new MomentUtils(instance: moment.tz('America/New_York'))).date();
Uncaught TypeError: _this.moment is not a function
at MomentUtils.date (/Users/slamb/git/tztest/node_modules/@date-io/moment/build/index.js:78:32)
> (new MomentUtils(instance: () => moment.tz('America/New_York'))).date();
Moment<2021-03-18T14:44:07-04:00>
> (new MomentUtils(instance: () => moment.tz('America/New_York'))).date('2021-01-01T00:00:00');
Moment<2021-03-18T14:44:19-04:00>
> (new MomentUtils(instance: (arg1, arg2, arg3, arg4) => moment.tz(arg1, arg2, arg3, arg4, 'America/New_York'))).date('2021-01-01T00:00:00');
Moment<2021-01-01T00:00:00-05:00>
> (new MomentUtils(instance: (arg1, arg2, arg3, arg4) => moment.tz(arg1, arg2, arg3, arg4, 'America/New_York'))).getCurrentLocaleCode();
Uncaught TypeError: _this.moment.locale is not a function
at MomentUtils.getCurrentLocaleCode (/private/tmp/tztest/node_modules/@date-io/moment/build/index.js:63:49)
> (new MomentUtils(instance: (arg1, arg2, arg3, arg4) => moment.tz(arg1, arg2, arg3, arg4, 'America/New_York'))).date();
Moment<2021-03-18T14:44:36-04:00>
> (new MomentUtils(instance: function() return moment(arguments).tz('America/New_York'); )).date()
...here the interpreter started making fun of me...
来自@date-io/moment
source,如下所述,我看到它以几种不同的方式使用它。当然,我希望所有这些都能正常工作。
export default class MomentUtils implements IUtils<defaultMoment.Moment>
...
constructor( locale, formats, instance : Opts = )
this.moment = instance || defaultMoment;
...
return /A|a/.test(this.moment().localeData().longDateFormat("LT"));
...
return this.moment.localeData().longDateFormat(token as LongDateFormatKey);
...
return this.locale || this.moment.locale();
...
return this.moment(value, format, this.locale, true);
...
return this.moment(value, format, true);
...
const moment = this.moment(value);
...
return this.moment.weekdaysShort(true);
【问题讨论】:
【参考方案1】:问题是 material-ui 有不同的文档和日期适配器集成 api 用于不同的主要版本。
我得到moment-timezone
与@material-ui/pickers@4.0.0-alpha.11
合作
依赖
"@material-ui/core": "4.11.3",
"@material-ui/pickers": "4.0.0-alpha.11",
"moment": "2.29.1",
"moment-timezone": "0.5.33",
"react": "17.0.2",
"react-dom": "17.0.2"
工作演示
https://codesandbox.io/s/material-ui-starter-template-forked-pvpmc
代码示例
import React from "react";
import render from "react-dom";
import momentTimezone from "moment-timezone";
import TextField from "@material-ui/core";
import DatePicker, LocalizationProvider from "@material-ui/pickers";
import MomentAdapter from "@material-ui/pickers/adapter/moment";
const App = () =>
const timeZoneFromServer = "Asia/Tokyo";
const moment = new MomentAdapter( instance: momentTimezone );
const dateWithTimeZone = moment().tz(timeZoneFromServer);
const handleDateChange = () => ;
return (
<LocalizationProvider dateAdapter=MomentAdapter>
<DatePicker
renderInput=(props) => <TextField ...props />
value=dateWithTimeZone
onChange=handleDateChange
/>
</LocalizationProvider>
);
;
render(<App />, document.getElementById("root"));
【讨论】:
差不多了!但我希望今天的指标是正确的,即使没有选择任何内容/value
是null
。所以我需要通过dateAdapter
以某种方式传递时区,而不是通过value
。 (另外,我用的是v5而不是v4,但我觉得差不多:your demo link adapted to v5)
如果您执行moment().tz('Some/Place')
不向moment()
调用传递任何参数,则立即将其设置为当前日期。这是你的预期输出吗?我编辑了我的示例以删除 .add(5, 'days')
调用...我不记得为什么要添加它。
你也可以moment.tz.setDefault('America/New_York')
。 momentjs.com/timezone/docs/#/using-timezones/default-timezone以上是关于远程时区的material-ui LocalizationProvider的主要内容,如果未能解决你的问题,请参考以下文章
Django:如何让 datetime 对象知道创建它的时区?
material-ui 'createSvgIcon' 不是从 '@material-ui/core/utils' 导出的