Do not set Time.zone to avoid timezone issues in Rails

Setting Time.zone in a Rails application changes time zone globally. Whenever Time.now is used in any other request, it uses whatever Time.zone is set to earlier. To avoid Time.zone issues, do not set Time.zone. Instead, use in_time_zone method to get time in desired zone.

Problem

The other day when going through code, found out a method with an argument time_zone. The time_zone argument was used to set Time.zone. The code below Time zone set, was calculating some times, which required the zone to be used which was passed in as an argument.

def perform_something_at(time_zone)
  Time.zone = time_zone
  some_date = Time.zone.yesterday.to_date
  # process(some_date)
end

Setting Time.zone sets the time zone, and is changed at application level.

This causes time zone issues at other places. As other places do not want Time.zone to be changed dynamically.

Solution: Avoid Setting Time.zone

To resolve, the problem at all other plcaes, we started using in_time_zone method.

Usage
  time = Time.now
  time = time.in_time_zone('Asia/Kolkata')
  # Use time for whatever processing

Listing down the source code of the in_time_zone method.

  # File activesupport/lib/active_support/core_ext/date_and_time/zones.rb, line 19
  def in_time_zone(zone = ::Time.zone)
    time_zone = ::Time.find_zone! zone
    time = acts_like?(:time) ? self : nil

    if time_zone
      time_with_zone(time, time_zone)
    else
      time || self.to_time
    end
  end

This returns TimeWithZone object in time zone passed to it as an argument.

in_time_zone method is available on DateTime and Date as well.

Summary
  • Practice using in_time_zone zone to convert Time in the desired zone.
  • Use Time.current instead of Time.now if you prefer everything in UTC.
  • Use DateTime.current instead of DateTime.now if you prefer everything in UTC.