Read more

When using time zones, beginning_of_day / end_of_day is broken in Rails 2 for any Date or DateTime

Arne Hartherz
May 22, 2012Software engineer at makandra GmbH

Using beginning_of_day or end_of_day on Date or DateTime objects in Rails 2.x applications will never respect time zones, which is horrible.\
This is fixed in Rails 3, though.

Illustration online protection

Rails Long Term Support

Rails LTS provides security patches for old versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2)

  • Prevents you from data breaches and liability risks
  • Upgrade at your own pace
  • Works with modern Rubies
Read more Show archive.org snapshot

Even when using Date.current or DateTime.current you will get regular Time or DateTime objects:

>> Date.current.beginning_of_day.class
=> Time # not a ActiveSupport::TimeWithZone as expected
>> DateTime.current.beginning_of_day.class
=> DateTime # not a ActiveSupport::TimeWithZone as expected

This means that whenever you are using those values for database interaction, you'll end up scoping on the wrong records since the database representation of these dates is not converted to UTC:

>> Date.current.beginning_of_day.to_s(:db)
=> "2012-05-22 00:00:00"
>> DateTime.current.beginning_of_day.to_s(:db)
=> "2012-05-22 00:00:00"

You need to work around it yourself:

>> Date.current.beginning_of_day.in_time_zone(Time.zone).class
=> ActiveSupport::TimeWithZone # This is what you want.
>> Date.current.beginning_of_day.in_time_zone(Time.zone).to_s(:db)
=> "2012-05-21 22:00:00" # When on +0200, this is midnight's UTC.

>> DateTime.current.beginning_of_day.in_time_zone(Time.zone).class
=> ActiveSupport::TimeWithZone # This is what you want.
>> DateTime.current.beginning_of_day.in_time_zone(Time.zone).to_s(:db)
=> "2012-05-21 22:00:00" # When on +0200, this is midnight's UTC.

If you feel you have the balls for it, you could also monkey-patch beginning_of_day and end_of_day so it works correctly for Date and DateTime.

Posted by Arne Hartherz to makandra dev (2012-05-22 10:20)