Code Monkey home page Code Monkey logo

Comments (15)

MeLlamoPablo avatar MeLlamoPablo commented on May 12, 2024 16

I also ran into this. It is very counter intuitive, especially beacuse this option is mentioned in the docs.

import format from "date-fns-tz/format";

format(new Date('2020-09-14T13:30:00'), 'HH:mm', { timeZone: 'Etc/UTC' }); // 13:30
format(new Date('2020-09-14T13:30:00'), 'HH:mm', { timeZone: 'Europe/Madrid' }); // 13:30
format(new Date('2020-09-14T13:30:00'), 'HH:mm', { timeZone: 'America/New_York' }); // 13:30

This was very unexpected for me, because the only use case that I require this library for is to format a given date in a given timezone. If I have this string: 2020-09-14T13:30:00.000Z, date-fns will format it correctly in the user's timezone out of the box:

import format from "date-fns/format";

format(new Date('2020-09-14T13:30:00.000Z'), 'HH:mm'); // 15:30 for me as I'm in Europe/Madrid

But if I want to display it in Etc/UTC, what I intuitively thought of doing was:

import tzFormat from "date-fns-tz/format";

tzFormat(new Date('2020-09-14T13:30:00.000Z'), 'HH:mm', { timeZone: 'Etc/UTC' }); // 15:30 ??? I expected 13:30

It seems that what I actually have to do is:

import format from "date-fns/format";
import utcToZonedTime from "date-fns-tz/utcToZonedTime";

format(
    utcToZonedTime(new Date('2020-09-14T13:30:00.000Z'), 'Etc/UTC'),
    'HH:mm',
); // 13:30, as expected

Seems very weird to me because I'm inputting an UTC date, I shouldn't have to "convert it", I should just have to display it correctly.

In fact, the whole utcToZonedTime function seems weird to me. If I do this:

import utcToZonedTime from "date-fns-tz/utcToZonedTime";

utcToZonedTime(
    new Date('2020-09-14T13:30:00.000Z'),
    'America/New_York',
).toISOString(); // '2020-09-14T07:30:00.000Z'

I'm actually receiving a different UTC date? If we removed the time zone suffix it would make sense, but as it stand it doesn't, at least to me.

The way I see it, dates should always be stored in UTC, and the only time you want to "convert" them is when you're displaying them in a different time zone, hence why I expected the timeZone option in format to work out of the box.

from date-fns-tz.

benjaminparnell avatar benjaminparnell commented on May 12, 2024 3

Just ran into this. Looks like timeZone gets passed straight down to date-fns/format which doesn't do anything with that option.

from date-fns-tz.

fgblomqvist avatar fgblomqvist commented on May 12, 2024 3

@MeLlamoPablo I don't get the same results as you (I'm on date-fns-tz 1.0.10 which is the latest on npm since February 2020).

import { format } from 'date-fns';
import { utcToZonedTime } from 'date-fns-tz';

format(
  utcToZonedTime(new Date('2020-09-14T13:30:00.000Z'), 'Etc/UTC'),
  'yyyy/MM/dd HH:mm:ss zzz',
);

outputs: 2020/09/14 03:30:00 GMT-7 which is clearly not correct. In fact, it outputs in my current local timezone (PDT or GMT-7) no matter what I pass to utcToZonedTime.

from date-fns-tz.

marktnoonan avatar marktnoonan commented on May 12, 2024 3

@fgblomqvist in order to get the correct result for me, I needed to do what amounted to

import { utcToZonedTime, format } from 'date-fns-tz'; 

format( utcToZonedTime(new Date('2020-09-14T13:30:00.000Z'), { timeZone: 'Etc/UTC' }),
 'yyyy/MM/dd HH:mm:ss zzz'
, ); 

Note the format function imported from date-fns-tz, and passing the whole options object with timeZone key. I don't know why this is so troublesome though, it seems to contradict the docs to have to do this kind of thing.

from date-fns-tz.

marnusw avatar marnusw commented on May 12, 2024 2

Thanks @MeLlamoPablo, that sounds good. To be honest it's probably much less work to leave everything as is, and add the functions you have proposed. In fact, if you could just contribute tzFormat that would be brilliant. It can be the first function mentioned in the docs, since it seems the one most people are after. If it seems there are better ways to structure the API overall we can change it in a v2. I'll make a point of reviewing it asap once submitted.

In the interest of having the most sensibale functional programming variants, I'd propose swapping the last two parameters so we'll have:

tzFormat(date, 'America/New_York', 'HH:mm ZZ') // standard
tzFormat('HH:mm ZZ')('America/New_York')(date) // fp

As a side note, I recently switched to yarn v2 and that seems to have broken the tests on Travis; so feel free to go back to yarn v1 so we can actually run the tests through CI. (Unless Travis happens to have fixed the issue by now.)

from date-fns-tz.

marnusw avatar marnusw commented on May 12, 2024 2

The added formatInTimeZone function should avoid some of the confusion around utcToZonedTime and format.

from date-fns-tz.

clemeno avatar clemeno commented on May 12, 2024 1

the only time you want to "convert" them is when you're displaying them in a different time zone, hence why I expected the timeZone option in format to work out of the box.

I'm new to date-fns-tz after years of moment-timezone and have been confused by this behavior too.

It looks like the { timeZone?: string } option in date-fns-tz/format 's purpose is only for requesting a specific timezone to display in the resulting string but does absolutely no conversion on the given Date so we have to be careful about the conversions before this display-only step.

from date-fns-tz.

simlu avatar simlu commented on May 12, 2024 1

We use the above workaround @marktnoonan outlined for now

This looks like a longstanding issue. Is there any work on this planned or underway?

from date-fns-tz.

MeLlamoPablo avatar MeLlamoPablo commented on May 12, 2024 1

The last release has been in 2019 and there hasn't been a comment from any maintainer in this issue. @marnusw can we assume that either the package is abandoned or this issue in particular is in "won't fix" state?

No offense at all, I've tried maintaining open source projects too and ended up burning out. I totally understand it, but we would appreciate an acknowledgement πŸ™‚

If we are to fork or look for an alternative library, I'll elaborate a bit on my use case I described above:

I believe in an ideal world all dates are stored in UTC. In this ideal world, the only reason to ever worry about time zones is displaying dates in a time zone different than the user's local tz (i.e world clock, or an app that displays the time of an international envent in the user's time zone and the event's local timezone).

To fulfill that use case, I would only need a package that behaves like this:

import parseISO from "date-fns/parseISO";
import format from "date-fns/parseISO";
import tzFormat from "date-tz-format";

// This date is 13:30 in UTC and 15:30 in my local time zone (Europe/Madrid)
const date = parseISO('2020-09-14T13:30:00.000Z');

format(date, 'HH:mm'); // Should output "15:30", the locally formatted date
tzFormat(date, 'HH:mm', 'Etc/UTC'); // Should output "13:30", the date in the requested time zone
tzFormat(date, 'HH:mm', 'America/New_York'); // Should output "09:30", the date in the requested time zone

// Note: as the time of writing, it is June 10th.
// Differences in daylight savings could makes these values fluctuate.

Personally, that's all I need. Now, I can understand that this ideal scenario doesn't always happen. If a legacy back-end sent a date formatted in server time, one would need a helper to parse it too. For example:

const message = await getMessage();
message.date; // "2020-09-14 09:30" - This is sent by the back-end. Which time zone is it?

// Assuming the server is in America/New_York and the user is in Europe/Madrid:

import parse from 'date-fns/parse';
parse(message.date, "yyyy-MM-dd HH:mm", new Date(0)); // Outputs "2020-09-14T07:30:00.000Z"
// πŸ‘† But this is wrong! The back-end is sending its local date, but date-fns has no way of knowing that.
//    date-fns actually believes, based in the absence of a time zone, that the date is formatted in the
//    user's local time zone.

// We need to explicitly parse the date in America/New_York:

import tzParse from 'date-tz-parse';
tzParse(message.date, "yyyy-MM-dd HH:mm", "America/New_York", new Date(0)); // Outputs "2020-09-14T13:30:00.000Z"
// πŸ‘† This is correct! The date is properly interpreted ad America/New_York and is promptly converted to UTC
//    If we want to operate with this date, we will perform all operations in UTC.
//    If we want to format this date in the local time zone, we can use 'date-fns/format'.
//    If we want to format it in a different time zone, we can use the hypothetical 'date-tz-format'

These are the two possible use cases that I can think of. Use tzFormat/tzParse as gateways to and from the "outside world" (back-end and UI) and always keep dates as UTC internally.

I see no use case for zonedTimeToUtc and utcToZonedTime, and getTimeZoneOffset seems to be similar to the identically named method in the Date class. I'd appreciate if anyone can point out anything that I could be missing.

from date-fns-tz.

shaungrady avatar shaungrady commented on May 12, 2024

According to the docs:

To format a date to a string showing time for a specific time zone, which can be different from the system time zone, the format function can be combined with utcToZonedTime as shown in the example below. To clarify, the format function will never change the underlying date, it must be changed to a zoned time before passing it to format.

Here's how @vic08's function should be written: https://stackblitz.com/edit/typescript-f9ptde?file=index.ts

import { format, utcToZonedTime } from "date-fns-tz";
import parseISO from 'date-fns/parseISO'
import formatISO from 'date-fns/formatISO'

function getTimeString(dateInput: string, timeZone: string): string {
  // Only necessary if `dateInput` isn't always in UTC.
  const utcDateString = formatISO(parseISO(dateInput));
  const zonedDate = utcToZonedTime(utcDateString, timeZone);

  // The `timeZone` option isn't needed here since we're not
  // making use of the time zone format pattern (z..zzzz).
  return format(zonedDate, 'HH:mm', { timeZone })
}

console.log(
  getTimeString('2020-02-11T18:48Z', 'GMT') === '18:48'
)

If you're familiar with moment-timezone, the format function is equivalent to:

// The second arg of the `#tz` method is the `keepLocalTime` flag.
moment(date).tz('GMT', true).format('HH:mm')

from date-fns-tz.

imjordanxd avatar imjordanxd commented on May 12, 2024

Not sure if I'm using the API wrong, but something seems very wrong here:

console.log(utcToZonedTime("2000-01-01T00:00:00.000Z", 'UTC')) // 1999-12-31T13:00:00.000Z

The timestamp is already in UTC, so why does utcToZonedTime return UTC minus my timezone offset?

Much like @MeLlamoPablo has mentioned, the timeZone option in format doesn't exactly make sense to me and I expected it to behave differently. For reference, I live in Melbourne, Australia and this is the behaviour I'm experiencing:

const parsed = parseISO('2000-01-01T00:00:00.000Z');
console.log(tzFormat(parsed, 'MMM d, yy, HH:mm a', { timeZone: 'UTC' })); // "Jan 1, 00, 11:00 AM" - should be "Jan 1, 00, 00:00 AM"

from date-fns-tz.

marnusw avatar marnusw commented on May 12, 2024

@MeLlamoPablo why would you fork the library rather than contribute and submit PRs? Indeed I don't have time to work on it now, but a single library is always better than multiple forks.

I like your idea of tzFormat and tzParse. Those are probably the missing functions in this library. Right now you can do the first with a combination of utcToZonedTime and format, but that isn't always clear. tzFormat could be such a wrapper.

The reason you need utcToZonedTime and the inverse if so you can get a date instance to pass into a date picker library etc. String output is not the only use case. The function names could be more intuitive, but changing them would require a major release. There is an old issue with a v2 proposal.

I'd be more than happy to accept a PR with tests for the two functions you have proposed. If you actively contribute I will also gladly give you access to the repo. I will just give it some time since my experience has been that the eagerness of most to be involved only lasts until the use case in the application they are working on is addressed, which is also perfectly fine.

from date-fns-tz.

marnusw avatar marnusw commented on May 12, 2024

@imjordanxd for some reason certain timezones seem to return the wrong offsets, and in fact it has appeared to work fine in the UK around UTC and in the US, but not in Australia. I have not had time to investigate, so I honestly have no idea why this would be. If you can figure it out and submit a fix I know many people would be extremely grateful to you.

from date-fns-tz.

MeLlamoPablo avatar MeLlamoPablo commented on May 12, 2024

why would you fork the library rather than contribute and submit PRs? Indeed I don't have time to work on it now, but a single library is always better than multiple forks.

I absolutely agree. I think the best outcome for everyone is to collaborate in a single library rather than split up efforts. I was just describing a "Plan B" in case this library was abandoned, which it seemed to me judging by the last release date.

Which is fine, as I said I totally understand how demanding can open source work be.

If you're willing to review PRs then I'd like to contribute. I will start by reading #36 and contributing to the discussion. I don't have much time myself either but at least I can give my $.02 in an ideal v2 API.

from date-fns-tz.

MeLlamoPablo avatar MeLlamoPablo commented on May 12, 2024

@marnusw thanks for the great work! The new function is much more straightforward.

Also sorry that I didn't end up contributing. Anyway happy new year!

from date-fns-tz.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.