Closed jonathanong closed 5 years ago
Hi @jonathanong!
Could you provide an example of this behavior and what do you expect instead? Thanks!
Hi @gpbl.. I think you may have tagged me on accident.. I do love this library and would be more than happy to contribute. great stuff!
thanks @johnrhampton, I'm so sorry I meant to answer to @jonathanong :smile: i clicked on the wrong user!
no worries @gpbl!
Hi @gpbl, I think I know what @jonathanong means, an example using moment:
"2016-02-22T00:00Z"
,const date = '2016-02-22T00:00Z';
let m = moment(date);
let mu = moment.utc(date);
m.format('YYYY-MM-DD HH:mm');
// output: "2016-02-21 19:00"
mu.format('YYYY-MM-DD HH:mm');
// output: "2016-02-22 00:00"
When you create an instance of Date
object using UTC/GMT format, the value is shifted to the local timezone to represent a correct local time, which causes problems when you compare dates in modifiers (e.g. isSameDay
for selected day).
I hope my explanation is understandable at least a little bit. :smile:
oh sorry. i forgot to follow up. yes, what @janmyler says :) i always handle all my dates with moment.utc()
.
another option is just to pass a date format like YYYY-MM-DD
to date picker instead of a Date
object so that it never picked up the locale and because the time isn't relevant.
Thanks for the feedback! Sorry for the delay, as I'm currently on vacation.
So I take it, the issue is related to the DateUtils's isSameDay
function - right? It would help to have some code to test this behavior, as I don't understand the role of moment.js here. Or just wait some more days, when back I'll try to reproduce the issue by myself :)
So finally I could take my time and investigate more the issue.
I like the @jonathanong suggestion to add an option for using only UTC (aka GMT) dates. I think about a new boolean prop like useUTC
. Setting this prop to true
would make the calendar use native UTC function like getUTCFullYear
or getUTCDate
.
Now that tests have been cleaned up and upgraded to enzyme, it would definitely help to have a failing test about this issue. Someone could help reproducing the problem?
How to get date without timestamp and w/o timezone? Only date (00H 00M). Thank you
@code-by that is not that easy to implement since date calculations in javascript does consider timezones.
@gpbl I'm currently having issues with this because my CI and local environments are in different time zones, so my Jest snapshots keep failing when they are covering react-day-picker. Have you encountered that?
@robwise that's weird, could you share some of your code?
I use enzyme's shallow
renderer alongside the enzyme-to-json serializer. Then the test code is just:
import { shallow } from 'enzyme';
import DayPicker from 'react-day-picker';
it('works', () => {
const wrapper = shallow(<div><DayPicker /></div>);
expect(wrapper).toMatchSnapshot();
});
This will fail because JS Date
objects show up in the snapshot. On my computer, these Date objects have a timezone of GMT-5, but on the CI server they are GMT+0.
@robwise I remember now I've met this issue in my CI before. I usually set a fixed date to workaround the problem, e.g.<DayPicker initialMonth={new Date(2017, 5, 1)} />
.
However I'd like to fix this issue once for all :) This may be solved using Date.UTC()
within the component when specifying a new prop:
<DatePicker utc={true} />
We need to have a good test suite before. This means basically:
<DatePicker utc={true} initialMonth={new Date(2017, 5, 1)} />
?@gpbl I found a workaround that may be sufficient, just pass this env var when starting jest, like this:
NODE_ENV=test TZ='UTC' jest
This way when you run Jest it's always set to UTC timezone.
@robwise awesome, thanks for sharing! This is a Operating System feature, right?
I was under the impression it was a Node feature, but maybe I'm mistaken?
So did you fix it?
I know it's kindof a dumbass solution but I ended up feeding dates into date picker by first passing them through this function:
/**
* Strips the timezone from a date and returns a new, local, date object
* @param {String} Expects a date formatted like "2018-03-31T00:00:00.000Z"
*/
export const getLocallyFormattedDate = d => (d) ? moment(d.split("T")[0]).toDate() : new Date();
I've been using the TZ=UTC
env var solution for 6 months now and it works very well.
The problem is more with how inconsistent new Date() // or Date.parse()
is across browsers and even within its API.
This below runs in latest Chrome as of this writing:
// Executed with an env running TZ=UTC-8
new Date('2019-01-01')
// Mon Dec 31 2018 16:00:00 GMT-0800 (Pacific Standard Time)
// While Executed in TZ=UTC
new Date('2019-01-01')
// Tue Jan 01 2019 00:00:00 GMT+0000 (Greenwich Mean Time)
This is due to new Date()
treating date only input as UTC and effectively parsing 2019-01-01T00:00:00Z
and then converting it to local time.
An easy workaround if you don't care about the time is to instead use
const dateParts = '2019-01-01'.split('-')
// Executed with an env running TZ=UTC-8
new Date(dateParts[0], dateParts[1] - 1, dateParts[2], 0, 0, 0) // Note the dateParts[1] - 1, that's because month are 0 based.
// Tue Jan 01 2019 00:00:00 GMT-0800 (Pacific Standard Time)
// And Executed in TZ=UTC
new Date(dateParts[0], dateParts[1] - 1, dateParts[2], 0, 0, 0)
// Tue Jan 01 2019 00:00:00 GMT+0000 (Greenwich Mean Time)
This effectively forces the time that is now parsed in the current timezone and therefore the date is the expected one.
As a side note, Firefox seems to be handling the Date only input "correctly" as in: assuming it is in local time, the same way it works for all other input methods.
Hope this helps.
This has been really confusing. In my use case I want everyone to pick a date in UTC. Is this possible with this library? When I select a date such as 2019-02-03 in UTC, and I change the time zone to something way off on my PC, and I open the date 2019-02-03 which was previously selected in the date picker, it shows 02-02 as selected. Does selectedDays convert the Date to local time? Thanks.
For day picker input, it is possible to convert input value to date with local time as UTC time, and onDayChange convert the date back to normal.
Input: 01-01-2010 12:00:00 GMT+0100 (UTC=01-01-2010T11:00:00Z)
-> 01-01-2010 11:00:00 GMT+0100 (UTC=01-01-2010T10:00:00Z)
.
Input: 01-01-2010 12:00:00 GMT+0100 (UTC=01-01-2010T11:00:00Z)
-> 01-01-2010 13:00:00 GMT+0100 (UTC=01-01-2010T12:00:00Z)
.
I used this helper function:
// make date with local time to be as given date UTC time (and reverse - date with UTC time to be as given date local time).
function dateLocalAsUTC(date, reverse = false) {
retDate.setMinutes(retDate.getMinutes() + (retDate.getTimezoneOffset() * (reverse ? -1 : 1)));
return retDate;
};
I'm closing this, since in the upcoming release react-day-picker will be based on date-fns, and hopefully we won't have this issue anymore.
@gpbl The issue continues to occur even on v9, which uses date-fns. I'm in the UTC +5:30 timezone, and when I select a date, for example, 19/12/2024, it shifts to 18/12/2024. This happens because I handle all my dates in UTC, but the date picker operates in the local timezone, which is ahead of UTC, leading to the mismatch. Is there any solution to this, or would I need to patch it?
@gpbl The issue continues to occur even on v9, which uses date-fns. I'm in the UTC +5:30 timezone, and when I select a date, for example, 19/12/2024, it shifts to 18/12/2024. This happens because I handle all my dates in UTC, but the date picker operates in the local timezone, which is ahead of UTC, leading to the mismatch. Is there any solution to this, or would I need to patch it?
Hi @KamaniBhavin! Could you provide some code to replicate your issue?
i store my dates in GMT. my dates do not care about timestamps. i noticed that when using this library, dates are always shown based on the current timezone. this is annoying because from PST, when i select a date, the day before is actually selected in the calendar.
is there a way we can set the mode to GMT? my current work around is to create new date objects based on the current locale. works, but i'm not a fan of it.
thanks