Skip to content

Conversation

@hlascelles
Copy link

By default, even with Rails 8, a new Rails installation will not use timestamps with timezone by default. They are (arguably wrongly) without timezone. There is some discussion of that here: rails/rails#41084

It is agreed in that issue that it is Postgres best practice to use timezones, and Rails only uses without timezone defaults for legacy reasons. rails/rails#53687

eg, use these settings:

ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :timestamptz

# Rails config:
config.time_zone = "Europe/London"
config.active_record.default_timezone = :utc

This is my first submission, I understand if they styling isn't perfect 👍 .

Also, this is the first check (?) that looks at Rails config, so I wasn't quite sure how to do that part.

Resolves: #228

@gregnavis gregnavis added the new detector A detector for a new kind of problem. label Aug 1, 2025
Copy link
Owner

@gregnavis gregnavis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the submission! 🙇🏻 I left some feedback.


ActiveRecord::Base.establish_connection :primary

# Enable pgcrypto extension for PostgreSQL if needed (for gen_random_uuid)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this needed by the changes submitted in this PR? If not, let's remove this.

*.gem
Gemfile.lock
gemfiles/**.lock
/.idea
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems to be tool-specific, not project specific, and thus belongs to the system-wide or user-level gitignore, not a project .gitignore. Let's remove this entry.


def test_timestamp_without_time_zone_is_error
Context.create_table(:events) do |t|
t.column :occurred_at, :timestamp, null: false
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is null: false needed here? If not, let's get rid of it as it's irrelevant to what's being tested.


def test_timestamp_with_time_zone_is_ok
Context.create_table(:events) do |t|
t.timestamptz :occurred_at, null: false
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above re null.


def test_ignore_tables
Context.create_table(:events) do |t|
t.column :occurred_at, :timestamp, null: false
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above re null.


each_table(except: config(:ignore_tables)) do |table|
each_column(table, except: config(:ignore_columns)) do |column|
next unless timestamp_column?(column)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this method call necessary, given sql_type is checked below?

Comment on lines +47 to +48
check_rails_default_timezone
check_sql_adapter
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have config checkers now, so I suggest removing them for now. I'd like to think a bit more about how to make them work.

class ActiveRecordDoctor::Detectors::IncorrectTimestampTypeTest < Minitest::Test
def setup
skip unless postgresql?
ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type = :timestamptz
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we remove that and use timestamp or timestamptz in all test cases below?

Comment on lines +14 to +15
# Simulate column.sql_type as 'timestamp without time zone'
ActiveRecord::Base.connection.change_column :events, :occurred_at, "timestamp without time zone"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's pass the right type when the column is being created.

Comment on lines +69 to +82
def test_postgresql_adapter_datetime_type_timestamptz
return unless defined?(ActiveRecord::ConnectionAdapters::PostgreSQLAdapter)

assert_equal ActiveRecord::ConnectionAdapters::PostgreSQLAdapter.datetime_type, :timestamptz
end

def test_rails_config_time_zone_and_default_timezone
return unless defined?(Rails)
return unless Rails.respond_to?(:application)

# assert_equal ActiveRecord::Base.default_timezone, :utc
# Ensure that the default timezone is set to UTC in the application config
assert_equal Rails.application.config.active_record.default_timezone, :utc
end
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove configuration-related tests along with the corresponding production code.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

new detector A detector for a new kind of problem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Suggestion: Require timestamp columns to have timezone

2 participants