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

Merge pull request #18850 from kamipo/fix_rounding_problem_for_postgresql_timestamp_column

Fix rounding problem for PostgreSQL timestamp column
This commit is contained in:
Andrew White 2015-02-08 13:41:22 +00:00
commit 00222bc22a
5 changed files with 50 additions and 19 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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?

View file

@ -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)