title: Does anyone know how to appropriately deal with user timezones in rails 2.3?
body: <p>We're building a rails app that needs to display dates (and more importantly, calculate them) in multiple timezones.</p>
  
  <p>Can anyone point me towards how to work with user timezones in rails 2.3(.5 or .8)</p>
  
  <p>The most inclusive article I've seen detailing how user time zones are supposed to work is here: <a href="http://wiki.rubyonrails.org/howtos/time-zones" rel="nofollow">http://wiki.rubyonrails.org/howtos/time-zones</a>... although it is unclear when this was written or for what version of rails. Specifically it states that:</p>
  
  <p>"Time.zone - The time zone that is actually used for display purposes. This may be set manually to override config.time_zone on a per-request basis."</p>
  
  <p>Keys terms being "display purposes" and "per-request basis".</p>
  
  <p>Locally on my machine, this is true. However on production, neither are true. Setting Time.zone persists past the end of the request (to all subsequent requests) and also affects the way AR saves to the DB (basically treating any date as if it were already in UTC even when its not), thus saving completely inappropriate values.</p>
  
  <p>We run Ruby Enterprise Edition on production with passenger. If this is my problem, do we need to switch to JRuby or something else?</p>
  
  <p>To illustrate the problem I put the following actions in my ApplicationController right now:</p>
  
  <pre><code>def test
  p_time = Time.now.utc
  s_time = Time.utc(p_time.year, p_time.month, p_time.day, p_time.hour)
  
  logger.error "TIME.ZONE" + Time.zone.inspect
  logger.error ENV['TZ'].inspect
  logger.error p_time.inspect
  logger.error s_time.inspect
  
  jl = JunkLead.create!
  jl.date_at = s_time
  
  logger.error s_time.inspect
  logger.error jl.date_at.inspect
  
  jl.save!
  
  logger.error s_time.inspect
  logger.error jl.date_at.inspect
  
  
  render :nothing =&gt; true, :status =&gt; 200
  end
  
  
  def test2
  Time.zone = 'Mountain Time (US &amp; Canada)'
  logger.error "TIME.ZONE" + Time.zone.inspect
  logger.error ENV['TZ'].inspect
  
  render :nothing =&gt; true, :status =&gt; 200
  end
  
  
  def test3
  Time.zone = 'UTC'
  logger.error "TIME.ZONE" + Time.zone.inspect
  logger.error ENV['TZ'].inspect
  
  
  render :nothing =&gt; true, :status =&gt; 200
  end
  </code></pre>
  
  <h2>and they yield the following:</h2>
  
  <pre><code>Processing ApplicationController#test (for 98.202.196.203 at 2010-12-24 22:15:50) [GET]
  TIME.ZONE#&lt;ActiveSupport::TimeZone:0x2c57a68 @tzinfo=#&lt;TZInfo::DataTimezone: Etc/UTC&gt;, @name="UTC", @utc_offset=0&gt;
  nil
  Fri Dec 24 22:15:50 UTC 2010
  Fri Dec 24 22:00:00 UTC 2010
  Fri Dec 24 22:00:00 UTC 2010
  Fri, 24 Dec 2010 22:00:00 UTC +00:00
  Fri Dec 24 22:00:00 UTC 2010
  Fri, 24 Dec 2010 22:00:00 UTC +00:00
  Completed in 21ms (View: 0, DB: 4) | 200 OK [http://www.dealsthatmatter.com/test]
  
  
  Processing ApplicationController#test2 (for 98.202.196.203 at 2010-12-24 22:15:53) [GET]
  TIME.ZONE#&lt;ActiveSupport::TimeZone:0x2c580a8 @tzinfo=#&lt;TZInfo::DataTimezone: America/Denver&gt;, @name="Mountain Time (US &amp; Canada)", @utc_offset=-25200&gt;
  nil
  Completed in 143ms (View: 1, DB: 3) | 200 OK [http://www.dealsthatmatter.com/test2]
  
  
  Processing ApplicationController#test (for 98.202.196.203 at 2010-12-24 22:15:59) [GET]
  TIME.ZONE#&lt;ActiveSupport::TimeZone:0x2c580a8 @tzinfo=#&lt;TZInfo::DataTimezone: America/Denver&gt;, @name="Mountain Time (US &amp; Canada)", @utc_offset=-25200&gt;
  nil
  Fri Dec 24 22:15:59 UTC 2010
  Fri Dec 24 22:00:00 UTC 2010
  Fri Dec 24 22:00:00 UTC 2010
  Fri, 24 Dec 2010 15:00:00 MST -07:00
  Fri Dec 24 22:00:00 UTC 2010
  Fri, 24 Dec 2010 15:00:00 MST -07:00
  Completed in 20ms (View: 0, DB: 4) | 200 OK [http://www.dealsthatmatter.com/test]
  
  Processing ApplicationController#test3 (for 98.202.196.203 at 2010-12-24 22:16:03) [GET]
  TIME.ZONE#&lt;ActiveSupport::TimeZone:0x2c57a68 @tzinfo=#&lt;TZInfo::DataTimezone: Etc/UTC&gt;, @name="UTC", @utc_offset=0&gt;
  nil
  Completed in 17ms (View: 0, DB: 2) | 200 OK [http://www.dealsthatmatter.com/test3]
  
  Processing ApplicationController#test (for 98.202.196.203 at 2010-12-24 22:16:04) [GET]
  TIME.ZONE#&lt;ActiveSupport::TimeZone:0x2c57a68 @tzinfo=#&lt;TZInfo::DataTimezone: Etc/UTC&gt;, @name="UTC", @utc_offset=0&gt;
  nil
  Fri Dec 24 22:16:05 UTC 2010
  Fri Dec 24 22:00:00 UTC 2010
  Fri Dec 24 22:00:00 UTC 2010
  Fri, 24 Dec 2010 22:00:00 UTC +00:00
  Fri Dec 24 22:00:00 UTC 2010
  Fri, 24 Dec 2010 22:00:00 UTC +00:00
  Completed in 151ms (View: 0, DB: 4) | 200 OK [http://www.dealsthatmatter.com/test]
  </code></pre>
  
  <hr>
  
  <p>It should be clear above that the 2nd call to /test shows Time.zone set to Mountain, even though it shouldn't.</p>
  
  <p>Additionally, checking the database reveals that the test action when run after test2 saved a JunkLead record with a date of 2010-12-22 15:00:00, which is clearly wrong.</p>