Timezone prop not working in MUI_
Fixing your DateTimePicker when it won't follow the timezone prop
more random bugsQuick one here, talking about a minor thing I did at work for a form which
displays a <DateTimePicker />
component from the React @mui/x-date-pickers
library.
Specifically I was trying to use the timezone
prop to auto display the date in
a specific timezone. I found changing the prop did nothing, even when I'd added
a localization provider above it. (REMEMBER TO ADD A LOCALIZATION
PROVIDER!!!!)
I'll quickly explain what I did wrong...
The code I was using
Here's a minimal reproduction of the code I was using, it had a
LocalizationProvider
and TimePicker
from MUI, and the AdapaterDateFns
to
work with our projects date-fns
dependency.
1import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers'
2import { AdapterDateFns } from '@mui/x-date-pickers/AdapterDateFns'
3
4const EXAMPLE_TIMEZONES = [
5 'Australia/Brisbane',
6 'America/New_York',
7 'America/Los_Angeles',
8 'Europe/London',
9 'Europe/Paris',
10]
11
12const exampleDate = new Date()
13
14export default function MyComponent() {
15 const [exampleTzIndex, setExampleTzIndex] = useState(0)
16
17 const handleTimezoneChange = (event) => {
18 // Loop our example TZ's
19 setExampleTzIndex((prev) => (prev + 1) % EXAMPLE_TIMEZONES.length)
20 }
21
22 // Example timezone
23 const exampleTz = EXAMPLE_TIMEZONES[exampleTzIndex]
24
25 return (
26 <LocalizationProvider dateAdapter={AdapterDateFns}>
27 <TimePicker
28 timezone={exampleTz}
29 value={exampleDate}
30 label={exampleTz}
31 />
32 <div>
33 <button onClick={handleTimezoneChange}>
34 Change Timezone
35 </button>
36 </div>
37 </LocalizationProvider>
38 )
39}
An easy little component that will cycle endlessly through our example timezones when clicked.
Can you already see what I've done wrong?
It's painfully obvious now.
We should see the input change its timezone when we click the button, but we don't. What's wrong with this code?
We're using AdapterDateFns
in our LocalizationProvider
, date-fns
does not
support timezones by default.
The MUI docs do actually explicitly include this caution on the subpage about Localization and Timezone. The info can be easy to miss in my opinion.
At least, I missed it.
Maybe a console warn would be helpful if the adapter doesn't support timezones when the prop is used?
The solution
I had to add the dayjs library to the project, and then use the AdapterDayjs
for this single input.
Let's look at that code again...
1import { DateTimePicker, LocalizationProvider } from '@mui/x-date-pickers'
2import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs'
3import dayjs, { Dayjs } from 'dayjs'
4import utc from 'dayjs/plugin/utc'
5import timezone from 'dayjs/plugin/timezone'
6
7// We need to now "extend" DayJS with its TZ support
8dayjs.extend(utc)
9dayjs.extend(timezone)
10
11const EXAMPLE_TIMEZONES = [
12 'Australia/Brisbane',
13 'America/New_York',
14 'America/Los_Angeles',
15 'Europe/London',
16 'Europe/Paris',
17]
18
19// Initialize our Date as a DayJS object
20const exampleDate = dayjs.utc(new Date())
21
22export default function MyComponent() {
23 const [exampleTzIndex, setExampleTzIndex] = useState(0)
24
25 const handleTimezoneChange = (event) => {
26 // Loop our example TZ's
27 setExampleTzIndex((prev) => (prev + 1) % EXAMPLE_TIMEZONES.length)
28 }
29
30 // Example timezone
31 const exampleTz = EXAMPLE_TIMEZONES[exampleTzIndex]
32
33 return (
34 <LocalizationProvider dateAdapter={AdapterDateFns}>
35 <TimePicker
36 timezone={exampleTz}
37 value={exampleDate}
38 label={exampleTz}
39 onChange={(d: Dayjs | null) => {
40 if (!d) {
41 // Could be null, bail out
42 return
43 }
44
45 console.log('You changed the date to', d)
46 }}
47 />
48 <div>
49 <button onClick={handleTimezoneChange}>
50 Change Timezone
51 </button>
52 </div>
53 </LocalizationProvider>
54 )
55}
Everything should work as expected now, if required you can transform your DayJs
object back to a JS Date object with d.toDate()
.
Blew an hour on this one, hope it helps someone else!