This project is archived and is in readonly mode.
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 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 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 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 February 22nd, 2011 @ 03:00 PM
-
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.
-
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 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 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 March 1st, 2011 @ 07:47 AM
Sorry about the last two comments. This ain't obviously a bug but DST kicking in.. :(
-
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 ofEET
-
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 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 inThread.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 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
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>