Do not pass times to date attributes. Always convert times to dates when your application uses time zones.
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
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
.