Summary | Calendar breaks on DST start date |
Queue | Kronolith |
Queue Version | 4.2.2 |
Type | Bug |
State | Assigned |
Priority | 1. Low |
Owners | Horde Developers (at) |
Requester | jsveiga (at) it (dot) eng (dot) br |
Created | 04/10/2015 (3693 days ago) |
Due | |
Updated | 11/23/2017 (2735 days ago) |
Assigned | 11/23/2017 (2735 days ago) |
Resolved | |
Milestone | |
Patch | No |
Assigned to
State ⇒ Assigned
for referring to the (yet unknown to me) moment library!
with Chrome, for example, it will jump to the next day:
new Date(2017, 9, 15, 0, 0).toString();
"Sun Oct 15 2017 01:00:00 GMT-0200 (-02)"
be used anymore, this is not a bug with it. Nor it's a bug with Horde.
ECMAScript does not have specs regarding what happens when a local
time is set to an invalid moment. So each browser deals with it on its
own way.
In 2017, Brazil shifts to DST at 2017-10-14, precisely at the end of
23:59. So just before the clock turns to 00:00, it jumps do
2017-10-15, 01:00. So it creates a gap of missing local time.
Other countries do the same thing at 23:59 (Lebanon, Syria) and
others, such as US, do it at 02:00, when it jumps to 03:00, and others
do it at different moments. Every country that has DST will have gaps
of missing local times. The site www.timeanddate.com is the best
reference there is.
So when you try to create a date at an invalid moment in local time
with Chrome, for example, it will jump to the next day:
new Date(2017, 9, 15, 0, 0).toString();
?Sun Oct 15 2017 01:00:00 GMT-0200 (-02)?
Here, I set my computer to Brazil standard time and tried to ask
Chrome what is the local time in 2017-10-15 (9 is October because the
counter starts with 0), at midnight (00:00). Since midnight does not
exist on 2017-10-15, Chrome has jumped to 2017-10-15 01:00 and gave me
that answer.
If I do the same thing with Firefox, it jumps back to the day before:
new Date(2017, 9, 15, 0, 0).toString();
"Sat Oct 14 2017 23:00:00 GMT-0300"
So in various parts of kronolith.js, when it tries to create moments
at invalid local times, things get broken depending on the user's
browser and moment in time. This is also the reason why adding one day
to 2017-10-14 00:00 will return a result of 2017-10-14 23:00, instead
of 2017-10-15 00:00, when the user is on Firefox.
This is causing the day 2017-10-14 to appear duplicated in kronolith
dynamic view, as reported in the original post.
The Horde Calendar Picker will also not let you select the day
2017-10-15, because, such as Datejs, it always defaults new date
objects to midnight (00:00) and, as seen above, the moment 2017-10-15
00:00 simply does not exist in some local times. So when you select
2017-10-15 it returns 2017-10-14, if your computer is set to any date
before entering Brazil (and similar countries) DST.
This is why when a JS program is interested only in dates (not time)
and date calculations, it should *never* trust local time. It should
always use UTC time, because there are no gaps nor overlaps in UTC.
Another way of working around this issue is to default date creations
to 12:00, because no DST transitions ever occur in the middle of the
day, in any time zone. So it?s a safer way of doing date calculations
when the choice of trusting local times had already been made in the
first place.
Unfortunately, Datejs is old and abandoned and does not have full UTC support.
Moment.js (https://momentjs.com/) is a much better choice and updated
library. It also has a nice feature which is the UTC mode. While in
UTC mode, all display methods will display in UTC time instead of
local time. Additionally, while in UTC mode, all getters and setters
will internally use the Date#getUTC and Date#setUTC methods instead of
the Date#get and Date#set methods
(https://momentjs.com/docs/#/parsing/utc/). This way you won?t have to
trust local time when dealing with date calculations.
The best solution here, IMHO, would be to rewrite the parts of
kronolith the uses Datejs and make it use moment.js, activating the
UTC mode when necessary.
It should be possible to patch kronolith.js in order to make it create
dates at 12:00 (midday), when time does not matter, instead of
midnight. But the first solution (moment.js with UTC mode) seems more
elegant.
Anyway, this is definitely something that cannot be ignored by horde,
because different browser deals with invalid local times in different
manners and it does not seem to change in a near future.
between 23:00 and 00:00, as on the DST switch date this interval does
not exist.
My server is debian stable, with the debian horde packages.
Joao
and I don't know if your patch works on the new Horde packages.
We'll try it soon but maybe you already know if it is compatible.
Joao
Leonardo
Have you tried the simple workarounds I suggested in my comments?
abs,
Joao
State ⇒ Feedback
Taken from
#6is still correct.I sincerely don't understand why this bug is marked as Low priority. I
do understand that this is free software and most of you developers -
who I thank so much - make your valuable contributions in your free
time or in work breaks.
But I think that setting a higher priority to the bug may put it in
better condition to be solved, 'cause I imagine a
developer/contributor would direct his efforts based o bug's priority.
I want to apologize if this sounds rude or non-sense. I really
appreciate the heroic and many times self sacrificial work Horde guys
have been doing, both on developing and supporting the community. But
I would be more thankful if you consider the situation of the entire
Brazilian Horde community (among others).
I also would be really really happy if I could help more on this, but
my developer skills are so far from that.
I hope you understand.
Best regards,
Leonardo Lopes
New Attachment: dstbug.jpg
DST. For 2016 the duplicated day in the calendar is 15th of October.
Any patch to this would be utterly appreciated!
IMHO this should not be a low priority bug. It messes up people
calendars for an entire month, shifting days in such way that people
would easily miss an important meet or task.
State ⇒ Assigned
Priority ⇒ 1. Low
return "-1" when that happens
It is hard to call that a bug, because there is no "right" way to do
it. Just adding 1 to the month day number would be wrong, because
"Date" is actually a "DateTime", so the time has to be taken into
account too.
If you think about it, 00:00 - 00:59 October 18th 2015 does not exist
in my timezone because at 23:59:59.99 on the 17th you set your clock
to 01:00:00.00 (and each DST-using timezone has such gap).
So adding 1 day to "Oct 17th 00:00" cannot result in "Oct 18th 00:00"
as that is an invalid datetime in this timezone. IMO, the "best"
result would be that the .add or .next methods returned an "invalid
date", and left it to the calling program to decide what to do.
Instead, each implementation seems to "decide" what to return (in some
Android cases, it's 31/12/1969 00:00!).
So when we are just interested in the Date and not Time, it is much
safer to set the time to something far from 00:00 (some timezones
switch at 01:00) before doing date math.
to the next day, but add 24 hours. I guess.
switch days do not have 24h, the resulting "day" is not what is
expected (as it happens when building the week rows). This is why
setting the hour for something away from 00:00 solves it as in the
patch I sent: Although it may shift +-1h, it is still within the
expected day.
It seems that JS date arithmetic for DST is not really consistent
across browsers around 00:00 (I've found this detailing differences
even between IE9 and IE10; maybe related to the same issue:
https://msdn.microsoft.com/en-us/library/ie/jj863688%28v=vs.85%29.aspx).
So would be interesting to make Kronilith "immune" to that, so the
results are consistent across different browsers/platforms.
State ⇒ Feedback
desktop client, I can reproduce this now. The problem is that
calculations like Date.next().day() don't jump to the next day, but
add 24 hours. I guess.
New Attachment: calview.patch
--- kronolith.js.orig 2015-04-13 10:56:33.267068678 -0300
+++ kronolith.js 2015-04-13 11:13:42.304493201 -0300
@@ -514,6 +514,7 @@
var tbody = $('kronolith-month-body'),
dates = this.viewDates(date, view),
day = dates[0].clone();
+ day.setHours(15);
$('kronolithCurrent')
.update(this.setViewTitle(date, view, data));
@@ -879,6 +880,7 @@
week = this.viewDates(this.date, 'week'),
workweek = this.viewDates(this.date, 'workweek'),
dateString, td, tr, i;
+ day.setHours(15);
// Remove old calendar rows. Maybe we should only rebuild the minical
// if necessary.
set to a DST timezone (in my case, (UTC-3:00) Brasilia), and I'm using
Firefox 37.0.1.
The calendar uses javascript functions from the browser, but the
building of the calendar view is coming from Kronolith (for example
kronolith.js, updateView for the large calendar view).
So it seems in some js implementations, date arithmetic works
differently (one can argue if "different" is wrong or more strict),
but Kronolith should be aware of that and deal with it.
For example, for the large month view, simply doing this:
#############
--- kronolith.js.orig 2015-04-13 10:56:33.267068678 -0300
+++ kronolith.js 2015-04-13 11:03:01.578750995 -0300
@@ -514,6 +514,7 @@
var tbody = $('kronolith-month-body'),
dates = this.viewDates(date, view),
day = dates[0].clone();
+ day.setHours(15);
$('kronolithCurrent')
.update(this.setViewTitle(date, view, data));
#################
on the updateView function where it builds the month table, solves the
issue by moving the time away from 00:00, avoiding that adding
days/weeks to Date results in an unexpected day due to the DST switch
point.
Similar workarounds can be done for the other instances where DST is
causing problems.
State ⇒ Not A Bug
is a bug in your browser. Confirmed, because I cannot reproduce this
either by setting the timezone globally in the PHP configuration, or
setting it individually in the preferences.
Priority ⇒ 2. Medium
State ⇒ Unconfirmed
New Attachment: Desktop.zip
Patch ⇒ No
Milestone ⇒
Queue ⇒ Kronolith
Summary ⇒ Calendar breaks on DST start date
Type ⇒ Bug
To reproduce:
1 - set the timezone (php.ini) to one that has DST starting at 00:00
of a known date. For example, date.timezone = "America/Sao_Paulo".
2 - access the year or month view of the calendar on the month that
DTS starts (in this case, October) and look at the DST start date
Interestingly, Android is plagued by almost the exact same bug:
https://code.google.com/p/android/issues/detail?id=74754
This is caused by using datetime variables with the time unset (thus
00:00). There is no 00:00 on the DST start date (the clock "jumps"
from 23:59 to 01:00), so functions using that date return bad results
which are not handled properly.