This project is archived and is in readonly mode.

#3478 ✓invalid
Christian Weyer

ActiveSupport Time Calculators (beginning_of_year etc.) do not change the timezone when crossing DST boundaries

Reported by Christian Weyer | November 10th, 2009 @ 11:04 PM

The beginning_of_year, beginning_of_month, beginning_of_day, end_of_year, end_of_month, end_of_day functions wrongly assume that the beginning/end of the respective period always has the same timezone as the date it was calculated from.

In the following example for beginning_of_year this is only true when the date we calculate from lies not within the daylight savings time period.


DateTime.parse('2009-01-05 23:12:11 CET').beginning_of_year => Thu, 01 Jan 2009 00:00:00 +0100 DateTime.parse('2009-01-05 23:12:11 CET').beginning_of_year.utc => Wed, 31 Dec 2008 23:00:00 +0000

Gives the correct time for CET and in the database the correct time for UTC.

But when we do this in summer:

DateTime.parse('2009-06-05 23:12:11 CEST').beginning_of_year => Thu, 01 Jan 2009 00:00:00 +0200 DateTime.parse('2009-06-05 23:12:11 CEST').beginning_of_year.utc => Wed, 31 Dec 2008 22:00:00 +0000

the timezone is just kept. Although the beginning of the year (as well as the end of the year)
is not in the CEST zone, but CET. This leads to wrong data in the database when Rails transforms
the date to UTC, subtracting one hour too much.

Comments and changes to this ticket

  • jufemaiz

    jufemaiz March 9th, 2010 @ 11:27 AM

    I don't believe that this is an issue. If you look at the chaining for DateTime.parse('2009-01-05 23:12:11 CET').beginning_of_year.utc

    DateTime is parsing a date, then giving the beginning of that year (in local time). The returned date is then transformed to UTC.

    Resolving your issue would be more likely to apply the UTC first and work from a UTC perspective.

  • Geoff Buesing

    Geoff Buesing March 9th, 2010 @ 02:06 PM

    • State changed from “new” to “invalid”

    Indeed, this isn't an issue, you're just coming across a limitation of the DateTime class.

    The DateTime class doesn't have any knowledge of daylight savings time, unfortunately, which means that DateTime#beginning_of_year won't be able to adjust for that. In other words, DateTime#beginning_of_year will preserve the local offset of the DateTime instance it's called on, and just change the date and time values. That's the best we can do with the information given.

    DateTime.parse does have a limited understanding of time zones -- it understands that "CET" represents a +0100 offset in the beginning of the year, and that "CEST" represents a +0200 offset. But this is a very naive implementation:

    >> DateTime.parse('2009-01-05 23:12:11 CET')
    => Mon, 05 Jan 2009 23:12:11 +0100
    >> DateTime.parse('2009-01-05 23:12:11 CEST')
    => Mon, 05 Jan 2009 23:12:11 +0200

    ... I can force Jan 5 to be CEST, even though that's not correct.

    Best if you avoid DateTime.parse, unless you really want an instance of DateTime. If you need to parse a time from a string, and you know which time zone this time needs to be in, you can use TimeZone.parse:

    >> = 'Paris'
    => "Paris"
    >> '2009-06-05 23:12:11'
    => Fri, 05 Jun 2009 23:12:11 CEST +02:00
    >>'2009-06-05 23:12:11').beginning_of_year
    => Thu, 01 Jan 2009 00:00:00 CET +01:00

    Time.parse has the unfortunate behavior of interpreting nonsense as, which makes it pretty much unusable:

    >> Time.parse 'no time here'
    => Tue Mar 09 08:04:31 -0600 2010

    ... which is probably why you're using DateTime.parse. ( doesn't do this, fyi.)

  • Christian Weyer

    Christian Weyer March 9th, 2010 @ 02:18 PM

    I found a a way around this problem in the meantime as well, but I still think that the time span calculators should care about if the timezone needs to adjusted. Without that, the time zone support seems incomplete to me, or at least the documentation should make it very clear, that DST crossing time spans will be computed incorrectly. Otherwise people (like me) may assume rails time zone support works even in this more "difficult" cases.

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href=""></a>

People watching this ticket