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:
commit
00222bc22a
5 changed files with 50 additions and 19 deletions
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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)
|
||||
|
|
Loading…
Reference in a new issue