In my application I have: config.time_zone = 'Warsaw'
A strange issue I have, is that it seems like Rails are having problems with comparision of datetime fields.
If I change the datetime 1 hour back (and Warsaw is currently in timezone +0100), Rails won’t update the database, even if the field has changed. However, if I change the field once again, then the update will go to the database.
Example:
(Rails 3.1.0, ruby-1.9.2-p290, fresh rails app):
$ rails g model User starts_at:datetime
$ rake db:migrate
$ rails c
Loading development environment (Rails 3.1.0)
ruby-1.9.2-p290 :001 > u = User.create({:starts_at => "2011-01-01 10:00"})
SQL (21.3ms) INSERT INTO "users" ("created_at", "starts_at", "updated_at") VALUES (?, ?, ?) [["created_at", Tue, 13 Dec 2011 11:32:50 CET +01:00], ["starts_at", Sat, 01 Jan 2011 10:00:00 CET +01:00], ["updated_at", Tue, 13 Dec 2011 11:32:50 CET +01:00]]
=> #<User id: 1, starts_at: "2011-01-01 09:00:00", created_at: "2011-12-13 10:32:50", updated_at: "2011-12-13 10:32:50">
ruby-1.9.2-p290 :002 > u.starts_at
=> Sat, 01 Jan 2011 10:00:00 CET +01:00 # datetime created
ruby-1.9.2-p290 :003 > u.starts_at = "2011-01-01 09:00:00" # new datetime with one hour back
=> "2011-01-01 09:00:00"
ruby-1.9.2-p290 :004 > u.starts_at
=> Sat, 01 Jan 2011 09:00:00 CET +01:00 # changed datetime
ruby-1.9.2-p290 :005 > u.save
=> true
ruby-1.9.2-p290 :006 > u.starts_at = "2011-01-01 09:00:00"
=> "2011-01-01 09:00:00"
ruby-1.9.2-p290 :007 > u.save
(0.3ms) UPDATE "users" SET "starts_at" = '2011-01-01 08:00:00.000000', "updated_at" = '2011-12-13 10:33:17.919092' WHERE "users"."id" = 1
=> true
I’ve tested it in this fresh app, because I have a problem with this in larger application. What is going on? I’ve tried to browse the Rails code, tried to re-copy the relevant code ‘by-hand’ in console (like update, assign_attributes, even checked time_zone_conversion) and it worked, but not in ‘real world’..
looks like you stumbled on a similar issue.
The problem appears to be here:
https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/attribute_methods/dirty.rb#L62
When rails it testing if the value was changed it compares old & new:
If the difference in time is the UTC offset, the above erroneously succeeds (luckly the new cached value holds the intended change).
The next save/update compares with the new (and correct) cached value and marks the field as changed.
EDIT:
Done some tests, this works well for me:
https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/attribute_methods/time_zone_conversion.rb#L50
Change
to
Boris