aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/adapters/postgresql/timestamp_test.rb
blob: 8246b14b933305e8bc1ffd165ed17e65db6d20fc (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
require 'cases/helper'
require 'models/developer'
require 'models/topic'

class PostgresqlTimestampTest < ActiveRecord::TestCase
  class PostgresqlTimestampWithZone < ActiveRecord::Base; end

  self.use_transactional_fixtures = false

  setup do
    @connection = ActiveRecord::Base.connection
    @connection.execute("INSERT INTO postgresql_timestamp_with_zones (id, time) VALUES (1, '2010-01-01 10:00:00-1')")
  end

  teardown do
    PostgresqlTimestampWithZone.delete_all
  end

  def test_timestamp_with_zone_values_with_rails_time_zone_support
    with_timezone_config default: :utc, aware_attributes: true do
      @connection.reconnect!

      timestamp = PostgresqlTimestampWithZone.find(1)
      assert_equal Time.utc(2010,1,1, 11,0,0), timestamp.time
      assert_instance_of Time, timestamp.time
    end
  ensure
    @connection.reconnect!
  end

  def test_timestamp_with_zone_values_without_rails_time_zone_support
    with_timezone_config default: :local, aware_attributes: false do
      @connection.reconnect!
      # make sure to use a non-UTC time zone
      @connection.execute("SET time zone 'America/Jamaica'", 'SCHEMA')

      timestamp = PostgresqlTimestampWithZone.find(1)
      assert_equal Time.utc(2010,1,1, 11,0,0), timestamp.time
      assert_instance_of Time, timestamp.time
    end
  ensure
    @connection.reconnect!
  end
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
    keys.each { |k| assert_kind_of Time, k }
  end

  def test_load_infinity_and_beyond
    d = Developer.find_by_sql("select 'infinity'::timestamp as updated_at")
    assert d.first.updated_at.infinite?, 'timestamp should be infinite'

    d = Developer.find_by_sql("select '-infinity'::timestamp as updated_at")
    time = d.first.updated_at
    assert time.infinite?, 'timestamp should be infinite'
    assert_operator time, :<, 0
  end

  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)

    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 :null => true, :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 :null => true, :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 :null => true, :precision => 7
      end
    end
  end

  def test_postgres_agrees_with_activerecord_about_precision
    ActiveRecord::Base.connection.create_table(:foos) do |t|
      t.timestamps :null => true, :precision => 4
    end
    assert_equal '4', pg_datetime_precision('foos', 'created_at')
    assert_equal '4', pg_datetime_precision('foos', 'updated_at')
  end

  def test_bc_timestamp
    date = Date.new(0) - 1.week
    Developer.create!(:name => "aaron", :updated_at => date)
    assert_equal date, Developer.find_by_name("aaron").updated_at
  end

  def test_bc_timestamp_leap_year
    date = Time.utc(-4, 2, 29)
    Developer.create!(:name => "taihou", :updated_at => date)
    assert_equal date, Developer.find_by_name("taihou").updated_at
  end

  def test_bc_timestamp_year_zero
    date = Time.utc(0, 4, 7)
    Developer.create!(:name => "yahagi", :updated_at => date)
    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)
    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