February 23, 2016
This blog is part of our Rails 5 series.
MySQL 5.6.4 and up has added fractional seconds support for TIME, DATETIME, and TIMESTAMP values, with up to microseconds (6 digits) precision.
To add precision on datetime column we need to add limit option to it. By
default it is set to 0.
def change
add_column :users, :last_seen_at, :datetime, limit: 6
end
This adds precision(6) to last_seen_at column in users table.
Let's look at the some of the examples with different precision values.
The task here is to set end_of_day value to updated_at column.
user = User.first
user.updated_at
=> Mon, 18 Jan 2016 10:13:10 UTC +00:00
user.updated_at = user.updated_at.end_of_day
=> Mon, 18 Jan 2016 23:59:59 UTC +00:00
user.save
'UPDATE `users` SET `updated_at` = '2016-01-18 23:59:59.999999' WHERE `users`.`id` = 1'
user.updated_at
=> Mon, 18 Jan 2016 23:59:59 UTC +00:00
user.reload
user.updated_at
=> Mon, 18 Jan 2016 23:59:59 UTC +00:00
Everything looks good here.
But let's look at what happens when precision is set to 0.
user = User.first
user.updated_at
=> Mon, 18 Jan 2016 10:13:10 UTC +00:00
user.updated_at = user.updated_at.end_of_day
=> Mon, 18 Jan 2016 23:59:59 UTC +00:00
user.save
'UPDATE `users` SET `updated_at` = '2016-01-18 23:59:59.999999' WHERE `users`.`id` = 1'
user.updated_at
=> Mon, 18 Jan 2016 23:59:59 UTC +00:00
So far everything looks good here too. Now let's see what happens when we reload this object.
user.reload
user.updated_at
=> Tue, 19 Jan 2016 00:00:00 UTC +00:00
As we can clearly see after the reload updated_at value has been rounded off
from 2016-01-18 23:59:59.999999 to 2016-01-19 00:00:00. It might seem like a
small issue but notice that date has changed from 01/18 to 01/19 because of
this rounding.
Rails team fixed this issue by removing fractional part if mysql adapter does not support precision.
Here are the two relevant commits to this change.
user.updated_at
=> Tue, 19 Jan 2016 00:00:00 UTC +00:00
user.updated_at = user.updated_at.tomorrow.beginning_of_day - 1
=> Tue, 19 Jan 2016 23:59:59 UTC +00:00
user.save
'UPDATE `users` SET `updated_at` = '2016-01-19 23:59:59' WHERE `users`.`id` = 1'
user.reload
user.updated_at
=> Tue, 19 Jan 2016 23:59:59 UTC +00:00
If precision is not set then fractional part gets stripped and date is not changed.
If this blog was helpful, check out our full blog archive.