Do not pass times to date attributes. Always convert times to dates when your application uses time zones.
Background
A time-zoned Time
attribute on a Rails record is converted to UTC using to_s(:db)
to be stored, and converted back into the correct time zone when the record is loaded from the database. So when you are not on UTC, time objects will be converted as follows.
>> Time.current
=> Fri, 15 Mar 2013 11:56:03 CET +01:00
>> Time.current.to_s(:db)
=> "2013-03-15 10:56:03" # This is now UTC
Problem
That will blow up in your face when you send times to attributes that expect dates, just because those times will also be converted using to_s(:db)
and sent to MySQL. The database itself does not care about the (longer) value and just stores the date part.
This means that whenever you pass a time that is within X hours away from midnight (where X is your +UTC time difference) you will store incorrect dates:
# Just like above, but we're close to midnight:
>> Time.current
=> Sat, 01 Jan 2050 00:15:00 CET +01:00
>> Time.current.to_s(:db)
=> "2049-12-31 23:15:00" # This is the correct representation of our time.
# Now let's create a record:
>> SomeRecord.create! :my_date => Time.current
>> SomeRecord.last.my_date
=> Fri, 31 Dec 2049 # Boom.
Note how the date should be 01/01/2050 but is not. This is because of the UTC timestamp string being cut off by the database. After all, it wants to store a date, not a time.
When dealing with dates, remember to always pass dates. So use Date.current
, or if you want to say something like 3.days.from_now
you must make sure to convert it via 3.days.from_now.to_date
.