This project is archived and is in readonly mode.

#6246 ✓invalid
Jay Crouch

Time.zone is broken in most every version of rails including 3.x

Reported by Jay Crouch | January 3rd, 2011 @ 05:47 AM

Assuming the description of Time.zone here: http://wiki.rubyonrails.org/howtos/time-zones is accurate, Time.zone is completely broken.

1] Setting Time.zone persists across threads and even persists past each request; meaning setting this value changes the behavior of all threads permanently until changed again.

2] Setting Time.zone affects the way ActiveRecord saves datetime values to the Database. Assuming Time.zone is not set, and config.active_record.default_timezone & config.time_zone are set to UTC, a datetime like 'Fri, 31 Dec 2010 17:00:00 MST -07:00' is saved as 'Sat Jan 01 00:00:00 UTC 2011' (when assigned to a model and saved). Meaning AR is aware of and adjusts for timezones. When Time.zone is set to 'Arizona', AR disregards the UTC zone and saves the date in local format instead of UTC.

I've already written a long write up on the issue, including tests to reproduce the behavior, and a patch I wrote to make working with zones easier. http://stackoverflow.com/questions/4529387/does-anyone-know-how-to-...

My patch doesn't solve the core problem however, that Time.zone is not local or thread safe or ActiveRecord safe.

Please fix this.

Comments and changes to this ticket

  • Brian Morearty

    Brian Morearty February 3rd, 2011 @ 04:54 PM

    Hi,

    Regarding point #1, "Setting Time.zone persists across threads and even persists past each request; meaning setting this value changes the behavior of all threads permanently until changed again," I see this as a documentation error because the doc for zone= says to use a before_filter in your app. It can be solved at the app level by using an around_filter instead of a before_filter:

    around_filter :set_time_zone

    def set_time_zone

    old_time_zone, Time.zone = Time.zone, current_user.time_zone
    yield
    

    ensure

    Time.zone = old_time_zone
    

    end

  • Brian Morearty

    Brian Morearty February 3rd, 2011 @ 04:55 PM

    Whoops, formatting error.

    @@@ Ruby def set_time_zone

    old_time_zone, Time.zone = Time.zone, 'Mountain Time (US & Canada)'
    yield
    

    ensure

    Time.zone = old_time_zone
    

    end

    
    
  • Brian Morearty

    Brian Morearty February 3rd, 2011 @ 04:56 PM

    One more time.

        def set_time_zone
          old_time_zone, Time.zone = Time.zone, 'Mountain Time (US & Canada)'
          yield
        ensure
          Time.zone = old_time_zone
        end
    
  • Szymon Nowak

    Szymon Nowak February 22nd, 2011 @ 03:00 PM

    1. Rails store the current time zone in Thread.current[:time_zone], so it is possible and very likely that on production server if you change time zone in one request, it will still be changed in the next one. That's why you should reset the current time zone on every request using before filter, if you want it to be different per request. Setting per request locale (I18n.locale) works exactly in the same way.

    2. I'm not really sure what the problem is here. Here's an output from Rails 3.0.4 app:

    ruby-1.9.2-p180 :040 > Time.zone = "UTC"
     => "UTC" 
    ruby-1.9.2-p180 :041 > b = Beverage.create(:name => "Wine")
     => #<Beverage id: 3, name: "Wine", created_at: "2011-02-22 14:48:23", updated_at: "2011-02-22 14:48:23"> 
    ruby-1.9.2-p180 :042 > b.created_at
     => Tue, 22 Feb 2011 14:48:23 UTC +00:00 
    ruby-1.9.2-p180 :043 > b.created_at_before_type_cast
     => 2011-02-22 14:48:23 UTC 
    ruby-1.9.2-p180 :044 > Time.zone = "Arizona"
     => "Arizona" 
    ruby-1.9.2-p180 :045 > b = Beverage.create(:name => "Water")
     => #<Beverage id: 4, name: "Water", created_at: "2011-02-22 14:49:28", updated_at: "2011-02-22 14:49:28"> 
    ruby-1.9.2-p180 :046 > b.created_at
     => Tue, 22 Feb 2011 07:49:28 MST -07:00 
    ruby-1.9.2-p180 :047 > b.created_at_before_type_cast
     => 2011-02-22 14:49:28 UTC 
    ruby-1.9.2-p180 :048 >
    

    Both objects were saved in the database with time in UTC, but how it was displayed depends on the current time zone.

  • Vasilis Dimos

    Vasilis Dimos March 1st, 2011 @ 06:20 AM

    Apparently there is a timezone bug when adding a month to the date "28 Februar".

    Time.now.yesterday => Mon Feb 28 08:14:11 +0200 2011 Time.now.yesterday.zone => "EET" (Time.now.yesterday + 1.month).zone => "EEST" #!!!! (Time.now.yesterday + 1.year).zone => "EET" (Time.now.yesterday + 1.day).zone => "EET"

    ruby --version
    ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10.2.0]

    Rails 3.04

  • Vasilis Dimos

    Vasilis Dimos March 1st, 2011 @ 06:23 AM

    Apparently there is a timezone bug when adding a month to the date "28 Februar".

    >> Time.now.yesterday
    => Mon Feb 28 08:14:11 +0200 2011
    >> Time.now.yesterday.zone
    => "EET"
    >> Time.now.yesterday + 1.month
    => Mon Mar 28 08:14:23 +0300 2011
    >> (Time.now.yesterday + 1.month).zone
    => "EEST"
    >> (Time.now.yesterday + 1.year).zone
    => "EET"
    >> (Time.now.yesterday + 1.day).zone
    => "EET"
    

    ruby --version
    ruby 1.8.7 (2010-01-10 patchlevel 249) [i686-darwin10.2.0]
    Rails 3.04

  • Vasilis Dimos

    Vasilis Dimos March 1st, 2011 @ 07:47 AM

    Sorry about the last two comments. This ain't obviously a bug but DST kicking in.. :(

  • Lenary

    Lenary March 1st, 2011 @ 07:48 AM

    @vasilis could that be to do with the fact that one month from now is summer time, but 1 day wasn't, and 1 year puts you back into winter time again? I'm guessing that EEST is the summer version of EET

  • Tom Cocca

    Tom Cocca March 9th, 2011 @ 03:35 PM

    I am also having problems with the Time Zone issue especially when combined with daylight savings time. It seems that the DST does not take into account today's date, only the date that you are parsing. Example below:

    (same output in both a rails 2.3.5 and 3.0.3 console)

    Time.zone => #<ActiveSupport::TimeZone:0x1055848b8 @utc_offset=nil, @name="Eastern Time (US & Canada)", @current_period=nil, @tzinfo=#<TZInfo::TimezoneProxy: America/New_York>> Time.zone.now => Wed, 09 Mar 2011 10:30:19 EST -05:00 Time.zone.parse("2011-03-09 18:00:00") => Thu, 09 Mar 2011 18:00:00 EST -05:00 Time.zone.parse("2011-03-12 18:00:00") => Sat, 12 Mar 2011 18:00:00 EST -05:00 Time.zone.parse("2011-03-13 18:00:00") => Sun, 13 Mar 2011 18:00:00 EDT -04:00

    So, today is March 9, DST for EST kicks in on 03/13 at 2am. However when I parse a Date of '2033-03-13 18:00:00' on the 9th it is already showing that time with the EDT offset when this should not kick in until the 13th. It should continue to show times in EST until we are actually in EDT time.

  • Alex Sharp

    Alex Sharp March 15th, 2011 @ 06:33 PM

    The fact that Time.zone uses Thread.current to set the time zone means that Rails will not share this state across threads -- in other words, this is not a global setting. It will, however, share this state across requests, because Rails does not spawn a new thread for each request. Rails reuses existing threads to serve subsequent requests once the current request has completed.

    This behavior is definitely a bit of a gotcha, and maybe it's a failing in the ActionController implementation, but you have to remember to either a.) set Time.zone at the beginning of every request, or b.) unset Time.zone after every request (via an around filter). The reason is that once the current request has been served, that Thread will stay alive and process another request, and any state saved in Thread.current (including the time zone information) will be available in the next request.

    So yes, some state is shared from one request to the next, but it's within the same Thread. In other words, Rails is thread-safe in this area (because a single thread will only serve one request at a time), but your application code may not be.

    FWIW, we ran into this exact same problem, so I know where you're coming from ;)

  • Josh Kalderimis

    Josh Kalderimis March 16th, 2011 @ 06:27 PM

    • State changed from “new” to “invalid”
    • Importance changed from “” to “Low”

    As Alex has pointed out, #1 is not a bug or an issue, Rails is Thread safe and as long as you take Alexs advice into account you will be fine.

    As Szymon pointed out, #2 is not an issue either as AR behaves as it should with respect to timezones.

    I am closing this issue as invalid.

    If you can provide a failing test case for either issue then please open a new issue keeping the scope of the issue to a single point.

    Thanks,

    Josh

  • bingbing

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages