I wanted to just completely disregard the user's local timezone, and not even use it for display or for sending to the API. In order to do that, I used their timezone just to parse dates back and forth from my target api timezone (utc). This is working for me:
it's in momentjs b/c our code is old, can replicate in newer libs
const { timeZone: localTZ } = Intl.DateTimeFormat().resolvedOptions()
// The TZ format I want everything to be displayed and submitted as
const apiTZ = 'utc'
const [apiTime, setApiTime] = useState(moment.utc())
<DatePicker
onChange={date => {
const apiTimeFromPickerLocalDate = moment(date)
.tz(localTZ)
// change TZ without changing date/time
.tz(apiTZ, true)
.format()
setApiTime(apiTimeFromPickerLocalDate)
}}
selected={
moment(apiTime)
.tz(apiTZ)
// Display picker time in local TZ without changing date/time
.tz(localTZ, true)
.toDate()
}
</DatePicker>
Playground Version (link)
const localDate = moment(new Date()).format();
const { timeZone: localTZ } = Intl.DateTimeFormat().resolvedOptions();
const apiTZ = "utc";
const apiTimeFromPickerLocalDate = moment(localDate)
.tz(localTZ)
// change TZ without changing date/time
.tz(apiTZ, true)
.format();
const pickerTimeFromApiTime = moment(apiTimeFromPickerLocalDate)
.tz(apiTZ)
.tz(localTZ, true)
.toDate();
console.log("local time", localDate);
console.log("api time", apiTimeFromPickerLocalDate);
console.log("picker time", pickerTimeFromApiTime);
local time 2023-02-09T13:12:39-10:00
api time 2023-02-09T13:12:39Z
picker time Thu Feb 09 2023 13:12:39 GMT-1000 (Hawaii-Aleutian Standard Time)