I tried different workarounds of this issue but at the end most workable variant I created you can find below.
The main idea of this variant is to show the wanted TZ inside the input field, but display local TZ inside the calendar and timeList.
I would be grateful for your feedback.
Also see: https://github.com/jquense/react-widgets/issues/467 and https://github.com/jquense/react-widgets/issues/515


import React, { useState, useMemo, useCallback } from 'react';
import moment from 'moment-timezone';
import DateTimePickerOrigin from 'react-widgets/lib/DateTimePicker';
const monthShortNames = [
'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec',
];
const dayShortNames = ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'];
const DateTimePicker = (props) => {
const {
tz, // <-- tz you want to display, eg 'Etc/UTC'
min,
max,
value,
onChange,
...tail
} = props;
const [localTz] = useState(moment.tz.guess());
const fixedParse = useCallback(
(dateStr) => (dateStr ? new Date(dateStr) : null),
[],
);
const fixedFormat = 'MMM D, YYYY HH:mm z';
const fixedTimeFormat = useCallback(
(date) => {
if (localTz !== tz) {
return `${moment.tz(date, localTz).format('HH:mm z')} (${moment.tz(date, tz).format('HH:mm z')})`;
}
return moment.tz(date, localTz).format('HH:mm');
},
[tz, localTz, fixedFormat],
);
const fixedDateFormat = useCallback(
(date) => String(date.getDate()),
[],
);
const fixedYearFormat = useCallback(
(date) => String(date.getFullYear()),
[],
);
const fixedMonthFormat = useCallback(
(date) => monthShortNames[date.getMonth()],
[],
);
const fixedDayFormat = useCallback(
(date) => dayShortNames[date.getDay()],
[],
);
const fixedMin = useMemo(
() => (min === null ? undefined : min),
[min],
);
const fixedMax = useMemo(
() => (max === null ? undefined : max),
[max],
);
return (
<DateTimePickerOrigin
{...tail}
parse={fixedParse}
format={fixedFormat}
timeFormat={fixedTimeFormat}
dateFormat={fixedDateFormat}
yearFormat={fixedYearFormat}
monthFormat={fixedMonthFormat}
dayFormat={fixedDayFormat}
min={fixedMin}
max={fixedMax}
value={value}
onChange={onChange}
/>
);
};