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
Format method ignores the timeZone option #55
Comments
Just ran into this. Looks like |
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: 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 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 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 |
@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: |
@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 |
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. |
We use the above workaround @marktnoonan outlined for now This looks like a longstanding issue. Is there any work on this planned or underway? |
According to the docs:
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 // The second arg of the `#tz` method is the `keepLocalTime` flag.
moment(date).tz('GMT', true).format('HH:mm') |
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 Much like @MeLlamoPablo has mentioned, the 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" |
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 I see no use case for |
@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 The reason you need 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. |
@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. |
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. |
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 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.) |
The added |
@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! |
I'm getting unexpected output when using
format
method.this is valid for v2.10
consider this example:
01:48
looks like a value for my local timezone (Asia/Bangkok), but not GMTThe text was updated successfully, but these errors were encountered: