8000 time attributes falsely marked as changed due to date shift on timezone conversion · Issue #55118 · rails/rails · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content
time attributes falsely marked as changed due to date shift on timezone conversion #55118
Open
@opsys-saito

Description

@opsys-saito

Steps to reproduce

# frozen_string_literal: true

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "rails"
  gem "sqlite3"
end

require "active_record/railtie"
require "minitest/autorun"

# This connection will do for database-independent bug reports.
ENV["DATABASE_URL"] = "sqlite3::memory:"

class TestApp < Rails::Application
  config.load_defaults Rails::VERSION::STRING.to_f
  config.eager_load = false
  config.logger = Logger.new($stdout)
  config.secret_key_base = "secret_key_base"

  config.active_record.encryption.primary_key = "primary_key"
  config.active_record.encryption.deterministic_key = "deterministic_key"
  config.active_record.encryption.key_derivation_salt = "key_derivation_salt"

  config.time_zone = "Asia/Tokyo"
  config.active_record.default_timezone = :utc
end
Rails.application.initialize!

ActiveRecord::Schema.define do
  create_table :users, force: true do |t|
    t.time :created_at
  end
end

class User < ActiveRecord::Base
end

class BugTest < ActiveSupport::TestCase
  def test_time_attribute_changed
    user = User.create! created_at: "08:00"
    user.reload

    user.created_at
    # => 2000-01-02 08:00:00.000000000 JST +09:00

    user.created_at = "08:00"
    user.created_at
    # => 2000-01-01 08:00:00.000000000 JST +09:00

    assert_equal [], user.changed_attribute_names_to_save
    # => ["created_at"]  ← unexpected!
  end
end

Although the same "08:00" value is assigned again, Active Record considers the attribute as changed.


Expected behavior

The created_at attribute should not be marked as changed when assigning the same time string ("08:00") again.
This should hold true even when the application and database time zones differ, and internal Time objects have different date parts.


Actual behavior

Assigning "08:00" again results in :created_at being marked as changed.

This happens because:

user.created_at.to_s
# => "2000-01-01 08:00:00 +0900"

user.created_at.utc.to_s
# => "1999-12-31 23:00:00 UTC"

Due to the timezone conversion, the internal Time object has a different date, triggering false positives in dirty tracking.


Proposal

I propose introducing a config option such as:

config.active_record.use_fixed_date_for_time_attributes = true

When enabled, Active Record would normalize time-typed values to a fixed date (e.g., 2000-01-01) internally.
This would eliminate unnecessary dirty tracking caused by timezone-induced date mismatches, while preserving timezone support and default behavior unless explicitly enabled.

Would the Rails team be open to such a feature?


System configuration

Rails version: 7.x.x
Ruby version: 3.x.x

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      0