Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Problem with fromZonedTime #302

Open
ggPeti opened this issue Sep 25, 2024 · 1 comment
Open

Problem with fromZonedTime #302

ggPeti opened this issue Sep 25, 2024 · 1 comment

Comments

@ggPeti
Copy link

ggPeti commented Sep 25, 2024

The docstring from fromZonedTime claims:

Returns a date instance with the UTC time of the provided date of which the values represented the local time in the time zone specified.

First of all, "of which the values represented" seems like sleazy terminology, but this may be just a wording issue. Investigating further however we find that it is not. There's a real issue with this function rendering it impractical outside of environments with UTC as the local time zone.

Let's take a look at what it does:

date.getFullYear(),
date.getMonth(),
date.getDate(),
date.getHours(),
date.getMinutes(),
date.getSeconds(),
date.getMilliseconds()

Hmm, so these are the "values". Let's check what getHours does:

The getHours() method of Date instances returns the hours for this date according to local time.

Emphasis mine. So if this function is run in an environment where Intl.DateTimeFormat().resolvedOptions().timeZone resolves to 'Etc/GMT-2', we will receive local time values in 'Etc/GMT-2' here. But alright, let's carry on, maybe this is accounted for somewhere...

but unfortunately it is not. These values are passed on to newDateUTC, which suddenly treats them as UTC values:

utcDate.setUTCFullYear(fullYear, month, day)
utcDate.setUTCHours(hour, minute, second, millisecond)

So we took a Date, converted it into the local time zone, then reinterpreted its parts as UTC. Mmm-hmm. This all before the real payload of the function takes place, the promised time zone based offsetting:

const offsetMilliseconds = tzParseTimezone(timeZone, new Date(utc))

Unsurprisingly, this ends up returning incorrect values unless the local time zone is UTC.

I believe the error lies in an incorrect assumption that getHours will return "the hour component from a date record". Unfortunately, this is not the case. Date objects are not records in JavaScript - the only thing they store is number of milliseconds since the epoch.

As it stands, this function can only be reasonably used in UTC environments. I believe its documentation should be updated accordingly.

@pbaern
Copy link

pbaern commented Nov 19, 2024

I encountered that problem, too, and currently decided to work around it by

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);
};

knime-github pushed a commit to knime/knime-js-pagebuilder that referenced this issue Nov 19, 2024
See the open issue here: marnusw/date-fns-tz#302

UIEXT-941 (Date&Time widget displays always browser timezone)
knime-github pushed a commit to knime/knime-js-pagebuilder that referenced this issue Nov 20, 2024
See the open issue here: marnusw/date-fns-tz#302

UIEXT-941 (Date&Time widget displays always browser timezone)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants