aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib/active_support
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib/active_support')
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb34
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb10
2 files changed, 28 insertions, 16 deletions
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 008c7f151b..68585e8273 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -5,29 +5,28 @@ module ActiveSupport
include Comparable
attr_reader :time_zone
- def initialize(utc_time, time_zone, local_time = nil)
- @utc = utc_time
- @time = local_time
- @time_zone = time_zone
+ def initialize(utc_time, time_zone, local_time = nil, period = nil)
+ @utc, @time_zone, @time = utc_time, time_zone, local_time
+ @period = @utc ? period : get_period_and_ensure_valid_local_time
end
# Returns a Time instance that represents the time in time_zone
def time
- @time ||= time_zone.utc_to_local(@utc)
+ @time ||= utc_to_local
end
# Returns a Time instance that represents the time in UTC
def utc
- @utc ||= time_zone.local_to_utc(@time)
+ @utc ||= local_to_utc
end
alias_method :comparable_time, :utc
alias_method :getgm, :utc
alias_method :getutc, :utc
alias_method :gmtime, :utc
- # Returns the underlying TZInfo::TimezonePeriod for the local time
+ # Returns the underlying TZInfo::TimezonePeriod
def period
- @period ||= time_zone.period_for_utc(utc)
+ @period ||= time_zone.period_for_utc(@utc)
end
# Returns the simultaneous time in the specified zone
@@ -214,5 +213,24 @@ module ActiveSupport
result = result.in_time_zone(time_zone) if result.acts_like?(:time)
result
end
+
+ private
+ def get_period_and_ensure_valid_local_time
+ @time_zone.period_for_local(@time)
+ rescue ::TZInfo::PeriodNotFound
+ # time is in the "spring forward" hour gap, so we're moving the time forward one hour and trying again
+ @time += 1.hour
+ retry
+ end
+
+ # Replicating logic from TZInfo::Timezone#utc_to_local because we want to cache the period in an instance variable for reuse
+ def utc_to_local
+ ::TZInfo::TimeOrDateTime.wrap(utc) {|utc| period.to_local(utc)}
+ end
+
+ # Replicating logic from TZInfo::Timezone#local_to_utc because we want to cache the period in an instance variable for reuse
+ def local_to_utc
+ ::TZInfo::TimeOrDateTime.wrap(time) {|time| period.to_utc(time)}
+ end
end
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index a52eee3e7c..401b669a0a 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -183,14 +183,8 @@ class TimeZone
# Time.zone = "Hawaii" # => "Hawaii"
# Time.zone.local(2007, 2, 1, 15, 30, 45) # => Thu, 01 Feb 2007 15:30:45 HST -10:00
def local(*args)
- t = Time.utc_time(*args)
- begin
- result = local_to_utc(t)
- rescue TZInfo::PeriodNotFound
- t += 1.hour
- retry
- end
- result.in_time_zone(self)
+ time = Time.utc_time(*args)
+ ActiveSupport::TimeWithZone.new(nil, self, time)
end
# Returns an ActiveSupport::TimeWithZone instance representing the current time