Skip to content
This repository was archived by the owner on May 29, 2019. It is now read-only.

Fixes repeated dates - issue #1098 #1101

Closed
wants to merge 1 commit into from
Closed

Fixes repeated dates - issue #1098 #1101

wants to merge 1 commit into from

Conversation

jbruni
Copy link
Contributor

@jbruni jbruni commented Sep 30, 2013

No description provided.

@pkozlowski-opensource
Copy link
Member

@jbruni @bekos is there a way to write a test for this? I know that testing date related stuff is super-tricky so we might want to skip a test for this change, but if we can test it somehow it would be awesome. @bekos feel free to merge if this looks good to you (or I can merge it after your thumbs up).

@caitp
Copy link
Contributor

caitp commented Sep 30, 2013

What about something like this, using moment.js:

$.each([30, 60, 90, 120, ... /* each timezone in 30 minute intervals */], function(_, zone) {
  describe('timezone ' + zone, function() {
    // Test each month of the year
    $.each([0,1,2,3,4,5,6,7,8,9,10,11], function(_, month) {
      it('month should not contain repeated dates', function() {
        // Set $scope.date to the first date of this month, generating the date with moment(...).zone(zone).toDate()
        // Walk the table to make sure that from the start of the month until the end of the month, no dates are
        // repeated.
        //
        // Maybe do this for each date in the month too, for extra robustness?
      });
    });
  });
});

It would generate a lot of tests, and each test would have a runtime of like n^2 with a simple approach, so it would increase build time a fair bit. And it's not clear how valuable this sort of test is

@jbruni
Copy link
Contributor Author

jbruni commented Oct 2, 2013

Thanks to @bekos research at #1098 (comment), it became possible understand WHY the repeated date behaviour:

date/time = Oct 17, 00:00 ... "plus 1" becomes Oct 18, 00:00
date/time = Oct 18, 00:00 ... "plus 1" becomes Oct 19 00:00
date/time = Oct 19, 00:00 ... "plus 1" becomes Oct 19 23:00 !!!
date/time = Oct 19, 23:00 ... "plus 1" becomes Oct 20 23:00
date/time = Oct 20, 23:00 ... "plus 1" becomes Oct 21 23:00

I've just tried at the browser's JavaScript console - and it happens like above.

Due to the DST (Daylight Saving Time), somehow informed in the localization, the JavaScript "setDate" becomes unreliable. Right from my console:

> x
Sat Oct 19 2013 00:00:00 GMT-0300 (BRT)
> x.setDate(20)
1382234400000
> x
Sat Oct 19 2013 23:00:00 GMT-0300 (BRT)
> x.getDate()
19
> x.setDate(20)
1382317200000
> x.getDate()
20

You see? A setDate(20) followed by a getDate() returns 19. And thus we traced the bug with precision.

@bekos wondered "probably the whole directive should work with UTC dates"; I didn't know what to say at that time. Now, after some thinking and tests, my opinion is YES, the whole directive should work with UTC functions - this way no localization tricks will affect.

Why, in short, 19 + 1 = 19? Answer, in short: due to DST/localization tweaks entering the scene.

The clock is altered, localization is aware, result is more or less unpredictable (here in Brazil DST rules change according to the politicians mood).

So, for the datepicker to be in the safe and secure side, let's use the UTC functions.

We learned this:

  • with the UTC functions the GMT diff will always be zero (this is what defines the UTC: GMT+0000)
  • without the UTC functions, as we are painfully seeing, the GMT diff can vary ... sometimes it is GMT-0300 but suddenly it can became GMT-0200 and after "one day" maybe 23 or 25 hours passed, and we may be even at the same day!

In short:

  • UTC functions = fixed GMT
  • no UTC functions = variable GMT

I'd merge and deploy this PR to the live site immediately, as now we are at October, and the wrong calendar appears to us at AngularUI Bootstrap front page without the need of changing the month... not an easy request, I know, but let me request it anyway. At least, the specific datepicker's "getDates" function becomes safe.

Then, people who knows datepicker better may apply the UTC change through the whole directive.

Finally, regarding testing, I'm afraid I can't help, except by making questions and wondering:

  • As we know a specific locale + datetime where DST happens, should we use this context in some tests? Why not? This is a DST-start date. We should include a DST-end date too. If we want to test if the code is "locale/DST-crazyness-proof" we need to test the code against it. Right?
  • How to specify a specific locale to run the tests under? "moment.js" can help with this? It does not help to have a fixed GMT/timezone... the problem here is sudden a change in the GMT diff! (Caused by locale rules.)
  • Hmmm... before implementing, let's answer: what exactly are we testing? The calendar days? Well... it works in most conditions... it does not work if there is a change in the GMT... so, it seems the context/condition to put the tested things under is to have "changes in the GMT" during the tested period. How to simulate this? As suggested above... should and can we use a specific case we know there is a change in the GMT? [America/Sao_Paulo - from Oct 19 to Oct 20 2013] ???

@jbruni
Copy link
Contributor Author

jbruni commented Oct 2, 2013

Another possibility would be to generate the calendar not using these built-in JS functions...

@jbruni
Copy link
Contributor Author

jbruni commented Oct 29, 2013

@tersariolli - Indeed. I've checked February 2015, and it shows day 21 twice! The solution does not work...

I'd like to know why...

Have you seen this approach here? #1196 - Certainly not optimal - but as a workaround it seems to "fix" the issue better than this flawed PR.

A proper solution would be another approach, not necessarily using these built-in JavaScript getDate / setDate "unpredictable" functions... I mean: a complete rewrite, not a quick-and-dirty small fix.

@pkozlowski-opensource
Copy link
Member

@jbruni wouldn't working with the UTC dates be a solution here? Planning to look into it in the near future and the issue boils down to being able to reliably add one day to a given date.

@bekos
Copy link
Contributor

bekos commented Oct 29, 2013

From these dates is used only the date part, time part is irrelevant. So you can initialize the first date at 12pm (noon) and add 1 day without caring about timezone changes.

@jbruni
Copy link
Contributor Author

jbruni commented Oct 29, 2013

@pkozlowski-opensource - Surprisingly not, it seems. I've just checked February 2015 in my app (which is running with the patch applied), and it repeats the day 21. I've not investigated further... By now, I'm only surprised and intrigued...

Before any further consideration, it seems to me it is easier to "add one day to a given date" using a small set of simple and neat custom build functions - instead of using these built-in ones...

@jbruni
Copy link
Contributor Author

jbruni commented Oct 29, 2013

Or as @bekos is saying - by setting mid-day as time these changes won't break the date... This works and this is what really matters... It just does not "look and feel" very nice to have to apply such workarounds, but it is certainly easier, faster and cheaper than coding a whole new set of date calculation functions...

@pkozlowski-opensource
Copy link
Member

@jbruni interesting... There is always something new we can learn about JavaScript Date APIs :-) Using noon as a work-around should work, but I agree that somehow it "doesn't sound right" :-)

@chrisirhc
Copy link
Contributor

Regarding this, I say to use UTC dates as well.

Why:

  • All UTC dates/times are valid at face value (no DST, no GMT)
  • UTC dates/times can always be converted to a localized time

However, the same cannot be said for a localized time. DST creates "gaps" or "overlapping times" where there's 1 hour of invalid time (during the gap), and 1 hour of time (overlap) that doesn't mean anything unless you say it's with or without DST.

The user can then either by take their face value (year, month, day, hour, minute, second) or convert them from UTC to local time (and handle the discrepancies that come along with that).

@pkozlowski-opensource
Copy link
Member

@bekos I'm going to assign this PR for you for the review as you are more familiar with the code-base and I don't know what is the status of the rewrite.

@ghost ghost assigned bekos Jan 21, 2014
@bekos
Copy link
Contributor

bekos commented Jan 25, 2014

Closing this, as the issue is expected to be solved by #1599 using the "dirty" workaround :-)
The UTC fix seems like working for @jbruni who is located in Brazil but it is still playing with the edges and I am afraid that we will create issues with shifted dates.

@chrisirhc I see, but if you are saying to use globally UTC dates for the datepicker, I believe this will create a lot of problems with unexpected behavior. For example you can be at the last day of one month and the calendar to show the title of the next and so on. Other than this issue, using local dates is not a problem until now, and someone can covert to UTC with something like date.toUTCString(). Open to discuss further if you want :-)

@bekos bekos closed this Jan 25, 2014
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants