Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

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

#3037

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.

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

State: invalid
Milestone: none
Assigned to: nobody
Importance: none

Activity

  1. CancelProfileIsBroken
  2. John Trupiano
    John Trupiano

    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.

    September 26th, 2009 @ 04:23 PM

  3. John Trupiano
    John Trupiano

    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.

    September 26th, 2009 @ 04:30 PM

  4. David Trasbo
    David Trasbo

    +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.

    September 26th, 2009 @ 06:31 PM

  5. John Trupiano
    John Trupiano

    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?

    September 26th, 2009 @ 06:40 PM

  6. Geoff Buesing
    Geoff Buesing
    • 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.

    October 27th, 2009 @ 02:27 AM

  7. Ryan Bigg
    Ryan Bigg
    • Tag cleared.

    Automatic cleanup of spam.

    October 11th, 2010 @ 10:54 AM