Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Allow precision option for postgresql datetimes

This patch addresses the difficulty of retrieving datetime fields. By default, the database holds a higher precision than the time as a String.

This issue is discussed at length at the following links:
- [#3519](#3519)
- [#3520](#3520)

Also, kudos to @mattscilipoti
  • Loading branch information...
commit 6657ec9a0a05c1b3ddcb7aa679ebfdb7e0bc4959 1 parent a232831
@tonywok tonywok authored
View
12 activerecord/CHANGELOG.md
@@ -1,5 +1,17 @@
## Rails 4.0.0 (unreleased) ##
+* Added support for specifying the precision of a timestamp in the postgresql
+ adapter. So, instead of having to incorrectly specify the precision using the
+ `:limit` option, you may use `:precision`, as intended. For example, in a migration:
+
+ def change
+ create_table :foobars do |t|
+ t.timestamps :precision => 0
+ end
+ end
+
+ *Tony Schneider*
+
* Allow ActiveRecord::Relation#pluck to accept multiple columns. Returns an
array of arrays containing the typecasted values:
View
10 activerecord/lib/active_record/connection_adapters/postgresql_adapter.rb
@@ -187,6 +187,7 @@ def extract_limit(sql_type)
case sql_type
when /^bigint/i; 8
when /^smallint/i; 2
+ when /^timestamp/i; nil
else super
end
end
@@ -201,6 +202,8 @@ def extract_scale(sql_type)
def extract_precision(sql_type)
if sql_type == 'money'
self.class.money_precision
+ elsif sql_type =~ /timestamp/i
+ $1.to_i if sql_type =~ /\((\d+)\)/
else
super
end
@@ -1285,6 +1288,13 @@ def type_to_sql(type, limit = nil, precision = nil, scale = nil)
when 5..8; 'bigint'
else raise(ActiveRecordError, "No integer type has byte size #{limit}. Use a numeric with precision 0 instead.")
end
+ when 'datetime'
+ return super unless precision
+
+ case precision
+ when 0..6; "timestamp(#{precision})"
+ else raise(ActiveRecordError, "No timestamp type has precision of #{precision}. The allowed range of precision is from 0 to 6")
+ end
else
super
end
View
65 activerecord/test/cases/adapters/postgresql/timestamp_test.rb
@@ -27,4 +27,69 @@ def test_save_infinity_and_beyond
d = Developer.create!(:name => 'aaron', :updated_at => -1.0 / 0.0)
assert_equal(-1.0 / 0.0, d.updated_at)
end
+
+ def test_default_datetime_precision
+ ActiveRecord::Base.connection.create_table(:foos)
+ ActiveRecord::Base.connection.add_column :foos, :created_at, :datetime
+ ActiveRecord::Base.connection.add_column :foos, :updated_at, :datetime
+ assert_nil activerecord_column_option('foos', 'created_at', 'precision')
+ end
+
+ def test_timestamp_data_type_with_precision
+ ActiveRecord::Base.connection.create_table(:foos)
+ ActiveRecord::Base.connection.add_column :foos, :created_at, :datetime, :precision => 0
+ ActiveRecord::Base.connection.add_column :foos, :updated_at, :datetime, :precision => 5
+ assert_equal 0, activerecord_column_option('foos', 'created_at', 'precision')
+ assert_equal 5, activerecord_column_option('foos', 'updated_at', 'precision')
+ end
+
+ def test_timestamps_helper_with_custom_precision
+ ActiveRecord::Base.connection.create_table(:foos) do |t|
+ t.timestamps :precision => 4
+ end
+ assert_equal 4, activerecord_column_option('foos', 'created_at', 'precision')
+ assert_equal 4, activerecord_column_option('foos', 'updated_at', 'precision')
+ end
+
+ def test_passing_precision_to_timestamp_does_not_set_limit
+ ActiveRecord::Base.connection.create_table(:foos) do |t|
+ t.timestamps :precision => 4
+ end
+ assert_nil activerecord_column_option("foos", "created_at", "limit")
+ assert_nil activerecord_column_option("foos", "updated_at", "limit")
+ end
+
+ def test_invalid_timestamp_precision_raises_error
+ assert_raises ActiveRecord::ActiveRecordError do
+ ActiveRecord::Base.connection.create_table(:foos) do |t|
+ t.timestamps :precision => 7
+ end
+ end
+ end
+
+ def test_postgres_agrees_with_activerecord_about_precision
+ ActiveRecord::Base.connection.create_table(:foos) do |t|
+ t.timestamps :precision => 4
+ end
+ assert_equal '4', pg_datetime_precision('foos', 'created_at')
+ assert_equal '4', pg_datetime_precision('foos', 'updated_at')
+ end
+
+ private
+
+ def pg_datetime_precision(table_name, column_name)
+ results = ActiveRecord::Base.connection.execute("SELECT column_name, datetime_precision FROM information_schema.columns WHERE table_name ='#{table_name}'")
+ result = results.find do |result_hash|
+ result_hash["column_name"] == column_name
+ end
+ result && result["datetime_precision"]
+ end
+
+ def activerecord_column_option(tablename, column_name, option)
+ result = ActiveRecord::Base.connection.columns(tablename).find do |column|
+ column.name == column_name
+ end
+ result && result.send(option)
+ end
+
end
Please sign in to comment.
Something went wrong with that request. Please try again.