7

Rails 7 fixes timezone awareness for tsrange and tstzrange columns

 1 year ago
source link: https://blog.saeloun.com/2022/11/17/tsrange-timezone-bug
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Postgres has a fantastic collection of column types that makes it easy to store custom data. One such type are Ranges which allow you to store a range of values. For example, you can store a range of dates or a range of integers. When it comes to storing a range of timestamps, Postgres provides the tsrange and tstzrange column types which store a range of timestamps with and without timezones respectively.

Before

Let’s create a column in a Rails module to store a range of timestamps.

  # First we create a migration to add the column
  class AddTimestampRangeToEmployees < ActiveRecord::Migration[7.0]
    def change
      add_column :employees, :tenure, :tsrange, array: true
    end
  end

Now let’s store a range of timestamps in this column.

  ➜  rails c
  Loading development environment (Rails 7.0.2)
  irb(main):001:0> Employee.create!(tenure: 5.years.ago..DateTime.yesterday, name: "John")
  => #<Employee id: 1, tenure: ["2017-11-03 14:10:17.844978 UTC", "2022-11-03 14:10:17.844978 UTC"], name: "John">

This works as expected. However, if we set a timezone in the application config (and then make tsrange timezone aware), we get a TypeError.

  # config/application.rb
  config.time_zone = "Asia/Kolkata"
  ActiveRecord::Base.time_zone_aware_types += [:tsrange]

Now let’s try again!

  ➜  rails c
  Loading development environment (Rails 7.0.2)
  irb(main):001:0> Employee.create!(tenure: 5.years.ago..DateTime.yesterday, name: "John")
  /Users/swaathi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activesupport-7.0.2/lib/active_support/core_ext/range/each.rb:19:in `ensure_iteration_allowed': can't iterate from ActiveSupport::TimeWithZone (TypeError)
  /Users/swaathi/.rbenv/versions/3.1.2/lib/ruby/gems/3.1.0/gems/activesupport-7.0.2/lib/active_support/core_ext/range/each.rb:19:in `ensure_iteration_allowed': can't iterate from ActiveSupport::TimeWithZone (TypeError)

After

Thanks to this PR, the app timezone is now retained when storing a range of timestamps. Let’s try again!

  ➜  rails c
  Loading development environment (Rails 7.0.2)
  irb(main):001:0> Employee.create!(tenure: 5.years.ago..DateTime.yesterday, name: "John")
  => #<Employee id: 1, tenure: ["2017-11-03 13:36:14.419774000 IST +05:30", "2022-11-03 13:36:14.419774000 IST +05:30"], name: "John">

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK