Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

There was a problem

You must be a member of this account.

This project is archived and is in readonly mode.

Dirty datetime attributes lose time zone info

#3658

When modifying a datetime attribute of an ActiveRecord object, its history is saved but without time zone information. Example:

>> q.start_at
=> Tue, 24 Nov 2009 11:21:08 CET +01:00
>> q.start_at_was
=> Tue, 24 Nov 2009 11:21:08 CET +01:00
>> q.start_at = Time.zone.now
=> Tue, 05 Jan 2010 16:09:52 CET +01:00
>> q.start_at
=> Tue, 05 Jan 2010 16:09:52 CET +01:00
>> q.start_at_was
=> Tue Nov 24 10:21:08 UTC 2009

I would expect q.start_at_was to return the old CET value, also after the change.

q is an instance of a normal ActiveRecord object, start_at is a datetime column (served from a PostgreSQL 8.3 server with all timezones turned off). Using Rails 2.3.4, Ruby 1.8.6, on Mac OS X.

Reported by Jens · January 5th, 2010 @ 03:15 PM

State: resolved
Milestone: 2.3.6
Assigned to: Jeremy Kemper Jeremy Kemper
Importance: Medium

Activity

  1. Matthew Bass
    Matthew Bass

    +1, this this has bitten me as well

    February 22nd, 2010 @ 03:01 AM

  2. Darnell Brawner
    Darnell Brawner

    I am having the same issue using dirty attributes to create a change log.

    March 5th, 2010 @ 04:06 PM

  3. Jeremy Kemper
    Jeremy Kemper
    • State changed from new to open
    • Assigned user set to Jeremy Kemper
    • Milestone set to 2.3.6

    March 5th, 2010 @ 04:34 PM

  4. Kristopher Murata
    Kristopher Murata

    This is happening because when storing the old attributes on @changed_attributes hash the datetime attributes were being transformed from ActiveSupport::TimeWithZone to just Time:

    irb(main):007:0> p.created_at.class
    => ActiveSupport::TimeWithZone
    irb(main):009:0> p.created_at = Time.now
    => Thu Apr 08 00:59:46 -0400 2010
    irb(main):011:0> p.created_at.class
    => ActiveSupport::TimeWithZone
    irb(main):012:0> p.created_at_was.class
    => Time
    

    The funny part is that is that ActiveSupport::TimeWithZone objects are created on-the-fly by the module ActiveRecord::AttributeMethods::TimeZoneConversion which overwrite read/write methods for datetime/timestamp columns when ActiveRecord::Base.time_zone_aware_attributes = true, so when cloning (ActiveRecord::Base.clone_attribute_value) datetime attributes it was getting the object Time and not ActiveSupport::TimeWithZone.

    My approach on this patch is storing on @changed_attributes the actual ActiveSupport::TimeWithZone object when ActiveRecord::Base.time_zone_aware_attributes = true and the attribute is not on skip_time_zone_conversion_for_attributes hash.

    I don't know if it's the right way to attack this issue, it's just a try.. :)

    April 8th, 2010 @ 07:36 AM

  5. Kristopher Murata
    Kristopher Murata

    Ops, noticed that I broke one test by note keeping my time zone configurations inside my test scope. Attached another patch with tests written right.

    April 8th, 2010 @ 08:41 AM

  6. Repository
    Repository
    • State changed from open to resolved

    April 8th, 2010 @ 06:28 PM

  7. StuFF mc
    StuFF mc
    • Importance changed from to Medium

    Turns out the problem is the same (2.3.8) when accessing .attributes (http://api.rubyonrails.org/classes/ActiveRecord/Base.html#M001863). Eg:

    >> User.first.attributes["created_at"]
    => Sun Oct 04 22:36:44 UTC 2009
    >> User.first.created_at
    => Mon, 05 Oct 2009 00:36:44 CEST 02:00
    >> User.first.attributes_before_type_cast["created_at"]
    => "2009-10-04 22:36:44"
    
    >> User.first.created_at.class
    => ActiveSupport::TimeWithZone
    >> User.first.attributes["created_at"].class
    => Time
    >> User.first.attributes_before_type_cast["created_at"].class
    => String
    

    How can I "keep" the timezone when accessing ".attributes"?

    July 17th, 2010 @ 09:50 AM

  8. bingbing