Daylight Savings Time is not handled correctly
alexdowad opened this issue · 5 comments
Hi! Just watched your "lightning talk" from 2011 and my curiosity was piqued to see if your library does better than Rails' Active Support when it comes to doing arithmetic on dates...
(import 'java.util.Calendar 'java.util.TimeZone)
(def tz (TimeZone/getTimeZone "America/New_York"))
(def cal (m/local-cal))
(.setTimeZone cal tz)
(.set cal Calendar/MONTH 10)
(.set cal Calendar/DATE 1)
; DST ends on Nov 3 in EST...
(def config {:calendar (fn [] cal) :seed (fn [] (.getTimeInMillis cal))})
; get the period spanning the DST change...
(last (take 3 (m/periods conf :day)))
=> [#inst "2013-11-03T04:00:00.000-00:00" #inst "2013-11-04T04:59:59.999-00:00"]
You can see here that currently, Monotony incorrectly defines a "day" as a fixed 24 hours. Depending on where you are, a "day" can be 23 or 25 hours when going in or out of DST.
The way Rails handles all such cases really bugs me: when you are adding time intervals, it converts the interval down to an offset in seconds, then blindly adds that number of seconds without considering leap years, differences in the length of the different months, etc. Monotony has the right idea when it comes to years and months; it would be nice to handle hours/days correctly as well.
As an aside, thanks for making this library available!
Thanks for your interest in monotony!
In the example you cite, isn't the period returned 25 hours? It goes from 2013-11-03 at 4AM UTC, to 2013-11-03 at 4:59:59AM UTC (the instant just before 5AM UTC). If it were 24 hours, I'd expect to see 2013-11-03 at 4AM UTC to 2013-11-04 3:59:59AM UTC.
It's possible I'm just brainfarting here but it looks correct, I think.
Hi! The thing to remember here is (and this is what Rails gets wrong):
If I start with January 1, and ask for a date one month after that, I
expect to get February 1, followed by March 1, April 1, May 1, and so on. I
don't care if the duration of each month in milliseconds is the same or
not. Because I asked for "one month later", not 30 days or 720 hours or
43200 seconds, I expect to get the same date on the following month.
The same applies to days. If I start with 4:00am on November 3, and ask for
"one day later", it should give me 4:00am on November 4. I didn't ask for
24 hours or 1440 seconds, I asked for "one day".
In this case, I started with 4:00am on November 3, asked Monotony for "one
day later", and it gave me 5:00am on November 4.
On further thought, this is quite strange. If Monotony moved from one date
to the next by adding a fixed number of milliseconds, I would expect it to
err on the low side, not the high side, since clocks are turned back in
EST on November 3. (
http://www.timeanddate.com/worldclock/clockchange.html?n=179)
On Mon, Sep 9, 2013 at 3:14 PM, Alex Redington notifications@github.comwrote:
Thanks for your interest in monotony!
In the example you cite, isn't the period returned 25 hours? It goes from
2013-11-03 at 4AM UTC, to 2013-11-03 at 4:59:59AM UTC (the instant just
before 5AM UTC). If it were 24 hours, I'd expect to see 2013-11-03 at 4AM
UTC to 2013-11-04 3:59:59AM UTC.It's possible I'm just brainfarting here but it looks correct, I think.
—
Reply to this email directly or view it on GitHubhttps://github.com//issues/5#issuecomment-24072421
.
I think that is the the correct answer when expressed in UTC. You can tell the instants that are returned are in UTC by the offset in the two literals. 4AM UTC on Nov 3 is midnight Nov 3 in the New York Time Zone. 5AM UTC on Nov 4 is midnight Nov 4 in the New York Time Zone.
I think maybe there is a problem: the instants returned apparently have timezones set to UTC, while the config you have as your basis has its TZ data set to New York. Thus the presentation when Clojure prints them as reader literals has a misleading presentation (but correct semantic time).
However I think the underlying time based logic is 100% correct.
OK, I get it now. Congrats for getting this corner case exactly right!
Sorry for the false alarm!
On Mon, Sep 9, 2013 at 5:33 PM, Alex Redington notifications@github.comwrote:
I think that is the the correct answer when expressed in UTC. You can tell
the instants that are returned are in UTC by the offset in the two
literals. 4AM UTC on Nov 3 is midnight Nov 3 in the New York Time Zone. 5AM
UTC on Nov 4 is midnight Nov 4 in the New York Time Zone.I think maybe there is a problem: the instants returned apparently have
timezones set to UTC, while the config you have as your basis has its TZ
data set to New York. Thus the presentation when Clojure prints them as
reader literals has a misleading presentation (but correct semantic time).However I think the underlying time based logic is 100% correct.
—
Reply to this email directly or view it on GitHubhttps://github.com//issues/5#issuecomment-24086676
.
I think there's still a valid problem here, which is that even though the semantics are right, the presentation is misleading and confusing. With better presentation, you could look at two periods returned by monotony and intuitively know that it did the right thing on Nov 3rd and Nov 4th. I'll open another bug on the dates not reflecting the TZ data of the config.