1
0
Fork 0
mirror of https://github.com/rails/rails.git synced 2022-11-09 12:12:34 -05:00

Format the datetime string according to the precision of the datetime field.

Incompatible to rounding behavior between MySQL 5.6 and earlier.

In 5.5, when you insert `2014-08-17 12:30:00.999999` the fractional part
is ignored. In 5.6, it's rounded to `2014-08-17 12:30:01`:

http://bugs.mysql.com/bug.php?id=68760
This commit is contained in:
Ryuta Kamizono 2014-12-17 16:01:28 +09:00
parent ae419af666
commit 4157f5d172
4 changed files with 62 additions and 1 deletions

View file

@ -1,3 +1,14 @@
* Format the datetime string according to the precision of the datetime field.
Incompatible to rounding behavior between MySQL 5.6 and earlier.
In 5.5, when you insert `2014-08-17 12:30:00.999999` the fractional part
is ignored. In 5.6, it's rounded to `2014-08-17 12:30:01`:
http://bugs.mysql.com/bug.php?id=68760
*Ryuta Kamizono*
* Allow precision option for MySQL datetimes.
*Ryuta Kamizono*

View file

@ -688,7 +688,7 @@ module ActiveRecord
m.register_type(%r(datetime)i) do |sql_type|
precision = extract_precision(sql_type)
Type::DateTime.new(precision: precision)
MysqlDateTime.new(precision: precision)
end
m.register_type(%r(enum)i) do |sql_type|
@ -884,6 +884,22 @@ module ActiveRecord
TableDefinition.new(native_database_types, name, temporary, options, as)
end
class MysqlDateTime < Type::DateTime # :nodoc:
def type_cast_for_database(value)
if value.acts_like?(:time) && value.respond_to?(:usec)
result = super.to_s(:db)
case precision
when 1..6
"#{result}.#{sprintf("%0#{precision}d", value.usec / 10**(6 - precision))}"
else
result
end
else
super
end
end
end
class MysqlString < Type::String # :nodoc:
def type_cast_for_database(value)
case value

View file

@ -2,6 +2,9 @@ require 'cases/helper'
if mysql_56?
class DateTimeTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
class Foo < ActiveRecord::Base; end
def test_default_datetime_precision
ActiveRecord::Base.connection.create_table(:foos, force: true)
@ -50,6 +53,20 @@ if mysql_56?
assert_equal 4, mysql_datetime_precision('foos', 'updated_at')
end
def test_formatting_datetime_according_to_precision
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.datetime :created_at, precision: 0
t.datetime :updated_at, precision: 4
end
date = ::Time.utc(2014, 8, 17, 12, 30, 0, 999999)
Foo.create!(created_at: date, updated_at: date)
assert foo = Foo.find_by(created_at: date)
assert_equal date.to_s, foo.created_at.to_s
assert_equal date.to_s, foo.updated_at.to_s
assert_equal 000000, foo.created_at.usec
assert_equal 999900, foo.updated_at.usec
end
private
def mysql_datetime_precision(table_name, column_name)

View file

@ -2,6 +2,9 @@ require 'cases/helper'
if mysql_56?
class DateTimeTest < ActiveRecord::TestCase
self.use_transactional_fixtures = false
class Foo < ActiveRecord::Base; end
def test_default_datetime_precision
ActiveRecord::Base.connection.create_table(:foos, force: true)
@ -50,6 +53,20 @@ if mysql_56?
assert_equal 4, mysql_datetime_precision('foos', 'updated_at')
end
def test_formatting_datetime_according_to_precision
ActiveRecord::Base.connection.create_table(:foos, force: true) do |t|
t.datetime :created_at, precision: 0
t.datetime :updated_at, precision: 4
end
date = ::Time.utc(2014, 8, 17, 12, 30, 0, 999999)
Foo.create!(created_at: date, updated_at: date)
assert foo = Foo.find_by(created_at: date)
assert_equal date.to_s, foo.created_at.to_s
assert_equal date.to_s, foo.updated_at.to_s
assert_equal 000000, foo.created_at.usec
assert_equal 999900, foo.updated_at.usec
end
private
def mysql_datetime_precision(table_name, column_name)