This project is archived and is in readonly mode.

#3037 ✓invalid
ronin-41535 (at lighthouseapp)

Time.current.utc_offset and Time.zone.utc_offset are different during DST

Reported by ronin-41535 (at lighthouseapp) | August 12th, 2009 @ 12:14 AM

Asking a TimeZone for its utc_offset, and a TimeWithZone object in the same TimeZone for its utc_offset return different results. For example:

  >> Time.zone = "Eastern Time (US & Canada)"
  => "Eastern Time (US & Canada)"
  >> Time.zone.utc_offset
  => -18000
  >> Time.current.utc_offset
  => -14400

The offending code is in ActiveSupport::TimeZone#utc_offset:

  def utc_offset
    @utc_offset ||= tzinfo.current_period.utc_offset
  end

In contrast, ActiveSupport::TimeWithZone#utc_offset calls utc_total_offset on the underlying period:

  def utc_offset
    period.utc_total_offset
  end

I believe the implementation in ActiveSupport::TimeWithZone#utc_offset is correct, and propose that TimeZone's implementation also call utc_total_offset. This way, the two offsets match each other, and match the offset displayed when calling Time.current.

Comments and changes to this ticket

  • CancelProfileIsBroken
  • John Trupiano

    John Trupiano September 26th, 2009 @ 04:23 PM

    Verified that it's only a problem in DST.

      john-mbp:rails john$ ruby script/console 
      Loading development environment (Rails 3.0.pre)
      /Users/john/projects/rails/rails/config/environment.rb:11: warning: already initialized constant Application
      >> Time.zone = "Eastern Time (US & Canada)"
      => "Eastern Time (US & Canada)"
      >> Time.now
      => Sat Sep 26 11:19:42 -0400 2009
      >> Time.zone.utc_offset
      => -18000
      >> Time.current.utc_offset
      => -14400
      >> require 'timecop'
      => []
      >> Timecop.travel(2009, 12, 12)
      => Sat Dec 12 00:00:00 -0500 2009
      >> Time.zone.utc_offset
      => -18000
      >> Time.current.utc_offset
      => -18000
    

    Using Timecop to move ahead to Dec, these two methods do in fact return the same value. It would appear that Vladimir's assertion that they should both return 14400 during DST is correct.

  • John Trupiano

    John Trupiano September 26th, 2009 @ 04:30 PM

    Now that I think about this further, I'm not sure that a change is warranted. A TimeZone object exists outside of the context of an actual Time instance. It's somewhat arbitrary to return its utc_offset based on Time.now. In essence, I don't think a TimeZone should consult "now" when asked for its offset. A TimeWithZone object carries with it a specific Time instance, and so it makes sense for it to take DST into account.

    -1 on changing this.

  • David Trasbo

    David Trasbo September 26th, 2009 @ 06:31 PM

    +1 verified

    Given I don't misunderstand I'll have to disagree with John. I took a look at the docs for Time.current() ...

    Returns Time.zone.now when config.time_zone is set, otherwise just returns Time.now.
    

    and Time.zone() ...

    Returns the TimeZone for the current request, if this has been set (via Time.zone=).
    

    ... and concluded that since Time.current() depends on Time.zone() they should have the same utc_offset. Please do correct me if I'm wrong, though.

  • John Trupiano

    John Trupiano September 26th, 2009 @ 06:40 PM

    My point is that a TimeZone object exists in the absence of a specific time. It's a matter of responsibility. A TimeZone should only take DST into account if it's asked for its utc_offset in the context of a specific Time. Since this is not the case when calling Time.zone, it shouldn't just arbitrarily choose to consult Time.now to determine whether or not to include DST in its calculation.

    At no point does a call to Time.zone.utc_offset indicate the exact Time against which you want the utc_offset to be evaluated. If we instead had a function like Time.zone.utc_offset_for_time(a_time), then I'd say yes, we should be including DST in the offset.

    Anyone else feel strongly about this?

  • Geoff Buesing

    Geoff Buesing October 27th, 2009 @ 02:27 AM

    • State changed from “new” to “invalid”

    TimeZone#utc_offset (called when you call Time.zone.utc_offset) returns just the base UTC offset for the time zone; it doesn't take DST into consideration.

    This offset for user friendly display in time_zone_select. For example, the display of "Central Time (US & Canada) is "(GMT-06:00) Central Time (US & Canada)". This offset should not change over the course of the year -- it should always be GMT-06:00.

  • Ryan Bigg

    Ryan Bigg October 11th, 2010 @ 10:54 AM

    • Tag cleared.

    Automatic cleanup of spam.

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