Open Frans-L opened 2 years ago
Merits of function names aside, this is intended behaviour. When you are working with a zoned time you shouldn't be specifying that using a UTC time via an ISO string as you're doing, that defeats the purpose. Create a new date using the constructor directly, i.e. new Date(...)
, then pass that to zonedTimeToUtc
with the time zone and you'll get the correct UTC date out.
Put another way, if you have the correct UTC time to start with, why use date-fns-tz
at all?
@marnusw : I have many problems with understanding what this f-on does. Please, put somewhere in documentation what f-on does: it adds locale timezone offset and subtracts specified timezone offset to specified date. With this explanation misunderstanding will be impossible.
In order to be more clear I' suggestion next changes in documentation:
Current: Given a date and any time zone, returns a Date with the equivalent UTC time. More precise: Given a date, any time zone and local time zone (as a third hidden param), returns a Date with the equivalent UTC time.
Current: (picked in any time zone) More precise: (picked in whatever local time zone)
@marnusw I'm here because of material ui's x-datetime/picker. It is enforcing editing in a user's locale. What I'm building is a scientific app and it must be in UTC. So, I start with UTC, but the picker forces locale. I'm trying to override that back to UTC using date-fns-tz
. I can't believe how much I'm struggling to do this. I thought, by the name of this function, that I had found a path forward. I can't believe this picker doesn't have a UTC or ISO flag.
any update on this ?? facing the same issue: expected: "2022-11-07T15:30:00.000Z" result: Mon Nov 07 2022 16:30:00 GMT+0100 (Midden-Europese standaardtijd) code below add in codesanbox
import * as React from "react";
import TextField from "@mui/material/TextField";
import { AdapterDateFns } from "@mui/x-date-pickers/AdapterDateFns";
import { LocalizationProvider } from "@mui/x-date-pickers/LocalizationProvider";
import { DateTimePicker } from "@mui/x-date-pickers/DateTimePicker";
import { utcToZonedTime, zonedTimeToUtc } from "date-fns-tz";
export default function BasicDateTimePicker() {
const [value, setValue] = React.useState(
new Date("Mon Nov 07 2022 15:34:00 GMT+0100 (Midden-Europese standaardtijd)"));
return (
<LocalizationProvider dateAdapter={AdapterDateFns}>
<DateTimePicker
ampm={false}
renderInput={(props) => <TextField {...props} />}
label="DateTimePicker"
value={value}
onChange={(newValue) => {
console.log(newValue,"\n", newValue.toISOString(),"\n", zonedTimeToUtc(newValue,
Intl.DateTimeFormat().resolvedOptions().timeZone ) );
setValue(newValue);
}}
/>
</LocalizationProvider>
);
}
I agree that this function purpose is not understandable and the name is ambiguous. I though it was something useful to convert local dates to UTC, which is useful in several use cases...
Is there anything like that in date-fns?
It looks like need to remove the latest "Z" from "zonedTime" string:
test('zonedTimeToUtc', () => {
const zonedTime = '2022-02-02T17:00:00.000Z';
const timezone = 'Europe/Helsinki'; // YOUR TIMEZONE (e.g. Helsinki +2)
const converted = zonedTimeToUtc(zonedTime.replace('Z', ''), timezone);
expect(converted.toISOString()).toEqual('2022-02-02T15:00:00.000Z');
});
i'm also struggling with this, though my problem isn't exactly the same as OP
i'm trying to get the local EST date object and transform it to UTC
const local = new Date();
const utc = zonedTimeToUtc(local, "America/New_York");
console.log("🚀 ~ file: AddModal.tsx:149 ~ handleSubmit ~ local:", local);
console.log("🚀 ~ file: AddModal.tsx:150 ~ handleSubmit ~ utc:", utc);
output:
🚀 ~ file: AddModal.tsx:150 ~ handleSubmit ~ utc: Fri Feb 02 2024 20:03:59 GMT-0500 (Eastern Standard Time)
🚀 ~ file: AddModal.tsx:150 ~ handleSubmit ~ utc: Fri Feb 02 2024 20:03:59 GMT-0500 (Eastern Standard Time)
i'm pulling my hair out because of this. am i doing something wrong?
I am pretty sure that this problem (the original problem as well as this) is related to https://github.com/marnusw/date-fns-tz/issues/302.
I have been working around that other issue by recreating internal methods like so
import { toDate, type OptionsWithTZ } from "date-fns-tz";
// @ts-expect-error
import tzParseTimezone from "@@/node_modules/date-fns-tz/_lib/tzParseTimezone";
// @ts-expect-error
import tzPattern from "@@/node_modules/date-fns-tz/_lib/tzPattern";
export const fromZonedTime = (
date: string | Date,
timeZone: string,
options?: OptionsWithTZ,
) => {
if (typeof date === "string" && !date.match(tzPattern)) {
return toDate(
date,
Object.assign(Object.assign({}, options), { timeZone }),
);
}
date = toDate(date, options);
const offsetMilliseconds = tzParseTimezone(timeZone, date);
return new Date(date.getTime() + offsetMilliseconds);
};
export const toZonedTime = (
date: string | Date,
timeZone: string,
options?: OptionsWithTZ,
) => {
date = toDate(date, options);
const offsetMilliseconds = tzParseTimezone(timeZone, date, true);
return new Date(date.getTime() - offsetMilliseconds);
};
and with that also the problems above vanished.
It seems like that
zonedTimeToUtc
is not converting to UTC time, instead, it's converting to zoned time into your local time.Here's an example, in which you try to convert something from your timezone to UTC. However, nothing is changed, since the zoned is the same as your local time.
So, it seems like
zonedTimeToUtc
should be called aszonedTimeToLocal
.Tested with: