aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG.md11
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb18
-rw-r--r--activerecord/test/cases/adapters/mysql/datetime_test.rb17
-rw-r--r--activerecord/test/cases/adapters/mysql2/datetime_test.rb17
4 files changed, 62 insertions, 1 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index 9820a10067..136277b924 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -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*
diff --git a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
index ac62fb9825..d8431372ee 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -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
diff --git a/activerecord/test/cases/adapters/mysql/datetime_test.rb b/activerecord/test/cases/adapters/mysql/datetime_test.rb
index 1705fecce0..fadca1fcf4 100644
--- a/activerecord/test/cases/adapters/mysql/datetime_test.rb
+++ b/activerecord/test/cases/adapters/mysql/datetime_test.rb
@@ -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)
diff --git a/activerecord/test/cases/adapters/mysql2/datetime_test.rb b/activerecord/test/cases/adapters/mysql2/datetime_test.rb
index 1705fecce0..fadca1fcf4 100644
--- a/activerecord/test/cases/adapters/mysql2/datetime_test.rb
+++ b/activerecord/test/cases/adapters/mysql2/datetime_test.rb
@@ -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)