aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrew White <pixeltrix@users.noreply.github.com>2015-02-08 13:41:22 +0000
committerAndrew White <pixeltrix@users.noreply.github.com>2015-02-08 13:41:22 +0000
commit00222bc22aeb12b35c7dc7c51dc0bed69fd67ad8 (patch)
tree32d780f568088bbfa3519a0f8ca23137ca7d533a
parent31fafe0a3223b58e214c03c88a33d6ef4435f63c (diff)
parentf9839120379292cbc5da25f35311f457b08b44a8 (diff)
downloadrails-00222bc22aeb12b35c7dc7c51dc0bed69fd67ad8.tar.gz
rails-00222bc22aeb12b35c7dc7c51dc0bed69fd67ad8.tar.bz2
rails-00222bc22aeb12b35c7dc7c51dc0bed69fd67ad8.zip
Merge pull request #18850 from kamipo/fix_rounding_problem_for_postgresql_timestamp_column
Fix rounding problem for PostgreSQL timestamp column
-rw-r--r--activerecord/CHANGELOG.md7
-rw-r--r--activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb16
-rw-r--r--activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb9
-rw-r--r--activerecord/lib/active_record/type/date_time.rb21
-rw-r--r--activerecord/test/cases/adapters/postgresql/timestamp_test.rb16
5 files changed, 50 insertions, 19 deletions
diff --git a/activerecord/CHANGELOG.md b/activerecord/CHANGELOG.md
index c76f4f2c30..1470c6dec1 100644
--- a/activerecord/CHANGELOG.md
+++ b/activerecord/CHANGELOG.md
@@ -1,3 +1,10 @@
+* Fix rounding problem for PostgreSQL timestamp column.
+
+ If timestamp column have the precision, it need to format according to
+ the precision of timestamp column.
+
+ *Ryuta Kamizono*
+
* Respect the database default charset for `schema_migrations` table.
The charset of `version` column in `schema_migrations` table is depend
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 1ce5f5ae58..c29692d6ca 100644
--- a/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
+++ b/activerecord/lib/active_record/connection_adapters/abstract_mysql_adapter.rb
@@ -917,18 +917,10 @@ module ActiveRecord
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
+ private
+
+ def has_precision?
+ precision || 0
end
end
diff --git a/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb b/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb
index b9e7894e5c..2fe61eeb77 100644
--- a/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb
+++ b/activerecord/lib/active_record/connection_adapters/postgresql/oid/date_time.rb
@@ -5,6 +5,15 @@ module ActiveRecord
class DateTime < Type::DateTime # :nodoc:
include Infinity
+ def type_cast_for_database(value)
+ if has_precision? && value.acts_like?(:time) && value.year <= 0
+ bce_year = format("%04d", -value.year + 1)
+ super.sub(/^-?\d+/, bce_year) + " BC"
+ else
+ super
+ end
+ end
+
def cast_value(value)
if value.is_a?(::String)
case value
diff --git a/activerecord/lib/active_record/type/date_time.rb b/activerecord/lib/active_record/type/date_time.rb
index 5646ee61db..e8614b16e0 100644
--- a/activerecord/lib/active_record/type/date_time.rb
+++ b/activerecord/lib/active_record/type/date_time.rb
@@ -11,21 +11,28 @@ module ActiveRecord
end
def type_cast_for_database(value)
+ return super unless value.acts_like?(:time)
+
zone_conversion_method = ActiveRecord::Base.default_timezone == :utc ? :getutc : :getlocal
- if value.acts_like?(:time)
- if value.respond_to?(zone_conversion_method)
- value.send(zone_conversion_method)
- else
- value
- end
+ if value.respond_to?(zone_conversion_method)
+ value = value.send(zone_conversion_method)
+ end
+
+ return value unless has_precision?
+
+ result = value.to_s(:db)
+ if value.respond_to?(:usec) && (1..6).cover?(precision)
+ "#{result}.#{sprintf("%0#{precision}d", value.usec / 10 ** (6 - precision))}"
else
- super
+ result
end
end
private
+ alias has_precision? precision
+
def cast_value(string)
return string unless string.is_a?(::String)
return if string.empty?
diff --git a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
index eb32c4d2c2..8246b14b93 100644
--- a/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
+++ b/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
@@ -46,6 +46,8 @@ end
class TimestampTest < ActiveRecord::TestCase
fixtures :topics
+ class Foo < ActiveRecord::Base; end
+
def test_group_by_date
keys = Topic.group("date_trunc('month', created_at)").count.keys
assert_operator keys.length, :>, 0
@@ -135,6 +137,20 @@ class TimestampTest < ActiveRecord::TestCase
assert_equal date, Developer.find_by_name("yahagi").updated_at
end
+ def test_formatting_timestamp_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 pg_datetime_precision(table_name, column_name)