My app needs material-ui date and time pickers to operate on a remote time zone specified by the server. I'd like the today circle on the date picker to actually indicate today in the remote time zone, and I'd like to translate the datetimes in the remote time zone to seconds since 1970-01-01T00:00:00Z
.
I'm using the material-ui v5 alphas. The docs say that you specify a @date-io
adapter for your time library. Looks like there are four obvious options:
@date-io/date-fns
(based on date-fns and date-fns-tz has a broken remote time zone design. It uses Javascript Dates to represent that date and time in a remote time zone, but if the local time zone has a "spring forward" hour, there are times you can't represent. issue.@date-io/dayjs
(based on dayjs) doesn't handle daylight saving time correctly. issue@date-io/luxon
(based on luxon) looks promising@date-io/moment
(based on moment and moment-timezone) looks promising
so I want to specify an adapter for either luxon or moment that constructs dates in a particular zone.
Either library supports setting a global default time zone (luxon, moment), but I'd prefer to set a time zone when constructing a particular date adapter. Messing with global state based on the server response is gross.
I found a date-io issue that says:
You can pass moment-time zone right to the
libInstance
in this case it will use time zone set of the moment instance or global one
That's what I want! But I'm confused about exactly what this instance is supposed to be. It doesn't help that I'm pretty new to Javascript.
The @date-io/luxon
constructor doesn't seem to allow overriding instance like this today.
Trying to get the moment one to work:
$ 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...
From @date-io/moment
source, as quoted below, I see it uses it in several different ways. Naturally, I want all those to work properly.
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);
value
isnull
. So I need to pass the time zone through thedateAdapter
somehow, not throughvalue
. (Also, I'm using v5 rather than v4, but I think it's almost the same: your demo link adapted to v5) – Ingenue