Merge pull request #28147 from kmcphillips/master-time-freeze
Allow Time#to_time on frozen objects. Return frozen time rather than "RuntimeError: can't modify frozen Time"
This commit is contained in:
commit
ee33b9e93a
@ -208,6 +208,13 @@
|
|||||||
|
|
||||||
## Rails 5.1.0.beta1 (February 23, 2017) ##
|
## Rails 5.1.0.beta1 (February 23, 2017) ##
|
||||||
|
|
||||||
|
* Fixed bug in `DateAndTime::Compatibility#to_time` that caused it to
|
||||||
|
raise `RuntimeError: can't modify frozen Time` when called on any frozen `Time`.
|
||||||
|
Properly pass through the frozen `Time` or `ActiveSupport::TimeWithZone` object
|
||||||
|
when calling `#to_time`.
|
||||||
|
|
||||||
|
*Kevin McPhillips* & *Andrew White*
|
||||||
|
|
||||||
* Cache `ActiveSupport::TimeWithZone#to_datetime` before freezing.
|
* Cache `ActiveSupport::TimeWithZone#to_datetime` before freezing.
|
||||||
|
|
||||||
*Adam Rice*
|
*Adam Rice*
|
||||||
|
@ -12,11 +12,7 @@ module Compatibility
|
|||||||
mattr_accessor(:preserve_timezone, instance_writer: false) { false }
|
mattr_accessor(:preserve_timezone, instance_writer: false) { false }
|
||||||
|
|
||||||
def to_time
|
def to_time
|
||||||
if preserve_timezone
|
preserve_timezone ? getlocal(utc_offset) : getlocal
|
||||||
@_to_time_with_instance_offset ||= getlocal(utc_offset)
|
|
||||||
else
|
|
||||||
@_to_time_with_system_offset ||= getlocal
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
require "active_support/core_ext/date_and_time/compatibility"
|
require "active_support/core_ext/date_and_time/compatibility"
|
||||||
|
require "active_support/core_ext/module/remove_method"
|
||||||
|
|
||||||
class Time
|
class Time
|
||||||
prepend DateAndTime::Compatibility
|
include DateAndTime::Compatibility
|
||||||
|
|
||||||
|
remove_possible_method :to_time
|
||||||
|
|
||||||
|
def to_time
|
||||||
|
preserve_timezone ? self : getlocal
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -411,6 +411,15 @@ def to_datetime
|
|||||||
@to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
|
@to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Returns an instance of <tt>Time</tt>
|
||||||
|
def to_time
|
||||||
|
if preserve_timezone
|
||||||
|
@to_time_with_instance_offset ||= getlocal(utc_offset)
|
||||||
|
else
|
||||||
|
@to_time_with_system_offset ||= getlocal
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
# So that +self+ <tt>acts_like?(:time)</tt>.
|
# So that +self+ <tt>acts_like?(:time)</tt>.
|
||||||
def acts_like_time?
|
def acts_like_time?
|
||||||
true
|
true
|
||||||
@ -429,7 +438,7 @@ def blank?
|
|||||||
|
|
||||||
def freeze
|
def freeze
|
||||||
# preload instance variables before freezing
|
# preload instance variables before freezing
|
||||||
period; utc; time; to_datetime
|
period; utc; time; to_datetime; to_time
|
||||||
super
|
super
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -16,11 +16,13 @@ def setup
|
|||||||
def test_time_to_time_preserves_timezone
|
def test_time_to_time_preserves_timezone
|
||||||
with_preserve_timezone(true) do
|
with_preserve_timezone(true) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = Time.new(2016, 4, 23, 15, 11, 12, 3600).to_time
|
source = Time.new(2016, 4, 23, 15, 11, 12, 3600)
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
assert_equal @utc_offset, time.utc_offset
|
assert_equal @utc_offset, time.utc_offset
|
||||||
|
assert_equal source.object_id, time.object_id
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -28,11 +30,43 @@ def test_time_to_time_preserves_timezone
|
|||||||
def test_time_to_time_does_not_preserve_time_zone
|
def test_time_to_time_does_not_preserve_time_zone
|
||||||
with_preserve_timezone(false) do
|
with_preserve_timezone(false) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = Time.new(2016, 4, 23, 15, 11, 12, 3600).to_time
|
source = Time.new(2016, 4, 23, 15, 11, 12, 3600)
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
assert_equal @system_offset, time.utc_offset
|
assert_equal @system_offset, time.utc_offset
|
||||||
|
assert_not_equal source.object_id, time.object_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_time_to_time_frozen_preserves_timezone
|
||||||
|
with_preserve_timezone(true) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = Time.new(2016, 4, 23, 15, 11, 12, 3600).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_equal @utc_offset, time.utc_offset
|
||||||
|
assert_equal source.object_id, time.object_id
|
||||||
|
assert_predicate time, :frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_time_to_time_frozen_does_not_preserve_time_zone
|
||||||
|
with_preserve_timezone(false) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = Time.new(2016, 4, 23, 15, 11, 12, 3600).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_equal @system_offset, time.utc_offset
|
||||||
|
assert_not_equal source.object_id, time.object_id
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -40,7 +74,8 @@ def test_time_to_time_does_not_preserve_time_zone
|
|||||||
def test_datetime_to_time_preserves_timezone
|
def test_datetime_to_time_preserves_timezone
|
||||||
with_preserve_timezone(true) do
|
with_preserve_timezone(true) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1, 24)).to_time
|
source = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1, 24))
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
@ -52,7 +87,8 @@ def test_datetime_to_time_preserves_timezone
|
|||||||
def test_datetime_to_time_does_not_preserve_time_zone
|
def test_datetime_to_time_does_not_preserve_time_zone
|
||||||
with_preserve_timezone(false) do
|
with_preserve_timezone(false) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1, 24)).to_time
|
source = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1, 24))
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
@ -61,17 +97,47 @@ def test_datetime_to_time_does_not_preserve_time_zone
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_datetime_to_time_frozen_preserves_timezone
|
||||||
|
with_preserve_timezone(true) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1, 24)).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_equal @utc_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_datetime_to_time_frozen_does_not_preserve_time_zone
|
||||||
|
with_preserve_timezone(false) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = DateTime.new(2016, 4, 23, 15, 11, 12, Rational(1, 24)).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_equal @system_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_twz_to_time_preserves_timezone
|
def test_twz_to_time_preserves_timezone
|
||||||
with_preserve_timezone(true) do
|
with_preserve_timezone(true) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = ActiveSupport::TimeWithZone.new(@utc_time, @zone).to_time
|
source = ActiveSupport::TimeWithZone.new(@utc_time, @zone)
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
assert_instance_of Time, time.getutc
|
assert_instance_of Time, time.getutc
|
||||||
assert_equal @utc_offset, time.utc_offset
|
assert_equal @utc_offset, time.utc_offset
|
||||||
|
|
||||||
time = ActiveSupport::TimeWithZone.new(@date_time, @zone).to_time
|
source = ActiveSupport::TimeWithZone.new(@date_time, @zone)
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @date_time, time.getutc
|
assert_equal @date_time, time.getutc
|
||||||
@ -84,14 +150,16 @@ def test_twz_to_time_preserves_timezone
|
|||||||
def test_twz_to_time_does_not_preserve_time_zone
|
def test_twz_to_time_does_not_preserve_time_zone
|
||||||
with_preserve_timezone(false) do
|
with_preserve_timezone(false) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = ActiveSupport::TimeWithZone.new(@utc_time, @zone).to_time
|
source = ActiveSupport::TimeWithZone.new(@utc_time, @zone)
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
assert_instance_of Time, time.getutc
|
assert_instance_of Time, time.getutc
|
||||||
assert_equal @system_offset, time.utc_offset
|
assert_equal @system_offset, time.utc_offset
|
||||||
|
|
||||||
time = ActiveSupport::TimeWithZone.new(@date_time, @zone).to_time
|
source = ActiveSupport::TimeWithZone.new(@date_time, @zone)
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @date_time, time.getutc
|
assert_equal @date_time, time.getutc
|
||||||
@ -101,10 +169,59 @@ def test_twz_to_time_does_not_preserve_time_zone
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_twz_to_time_frozen_preserves_timezone
|
||||||
|
with_preserve_timezone(true) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = ActiveSupport::TimeWithZone.new(@utc_time, @zone).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_instance_of Time, time.getutc
|
||||||
|
assert_equal @utc_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
|
||||||
|
source = ActiveSupport::TimeWithZone.new(@date_time, @zone).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @date_time, time.getutc
|
||||||
|
assert_instance_of Time, time.getutc
|
||||||
|
assert_equal @utc_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_twz_to_time_frozen_does_not_preserve_time_zone
|
||||||
|
with_preserve_timezone(false) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = ActiveSupport::TimeWithZone.new(@utc_time, @zone).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_instance_of Time, time.getutc
|
||||||
|
assert_equal @system_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
|
||||||
|
source = ActiveSupport::TimeWithZone.new(@date_time, @zone).freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @date_time, time.getutc
|
||||||
|
assert_instance_of Time, time.getutc
|
||||||
|
assert_equal @system_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def test_string_to_time_preserves_timezone
|
def test_string_to_time_preserves_timezone
|
||||||
with_preserve_timezone(true) do
|
with_preserve_timezone(true) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = "2016-04-23T15:11:12+01:00".to_time
|
source = "2016-04-23T15:11:12+01:00"
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
@ -116,7 +233,8 @@ def test_string_to_time_preserves_timezone
|
|||||||
def test_string_to_time_does_not_preserve_time_zone
|
def test_string_to_time_does_not_preserve_time_zone
|
||||||
with_preserve_timezone(false) do
|
with_preserve_timezone(false) do
|
||||||
with_env_tz "US/Eastern" do
|
with_env_tz "US/Eastern" do
|
||||||
time = "2016-04-23T15:11:12+01:00".to_time
|
source = "2016-04-23T15:11:12+01:00"
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
assert_instance_of Time, time
|
assert_instance_of Time, time
|
||||||
assert_equal @utc_time, time.getutc
|
assert_equal @utc_time, time.getutc
|
||||||
@ -124,4 +242,32 @@ def test_string_to_time_does_not_preserve_time_zone
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_string_to_time_frozen_preserves_timezone
|
||||||
|
with_preserve_timezone(true) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = "2016-04-23T15:11:12+01:00".freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_equal @utc_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_string_to_time_frozen_does_not_preserve_time_zone
|
||||||
|
with_preserve_timezone(false) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
source = "2016-04-23T15:11:12+01:00".freeze
|
||||||
|
time = source.to_time
|
||||||
|
|
||||||
|
assert_instance_of Time, time
|
||||||
|
assert_equal @utc_time, time.getutc
|
||||||
|
assert_equal @system_offset, time.utc_offset
|
||||||
|
assert_not_predicate time, :frozen?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -431,11 +431,29 @@ def test_time_at
|
|||||||
assert_equal time, Time.at(time)
|
assert_equal time, Time.at(time)
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_to_time
|
def test_to_time_with_preserve_timezone
|
||||||
with_env_tz "US/Eastern" do
|
with_preserve_timezone(true) do
|
||||||
assert_equal Time, @twz.to_time.class
|
with_env_tz "US/Eastern" do
|
||||||
assert_equal Time.local(1999, 12, 31, 19), @twz.to_time
|
time = @twz.to_time
|
||||||
assert_equal Time.local(1999, 12, 31, 19).utc_offset, @twz.to_time.utc_offset
|
|
||||||
|
assert_equal Time, time.class
|
||||||
|
assert_equal time.object_id, @twz.to_time.object_id
|
||||||
|
assert_equal Time.local(1999, 12, 31, 19), time
|
||||||
|
assert_equal Time.local(1999, 12, 31, 19).utc_offset, time.utc_offset
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_to_time_without_preserve_timezone
|
||||||
|
with_preserve_timezone(false) do
|
||||||
|
with_env_tz "US/Eastern" do
|
||||||
|
time = @twz.to_time
|
||||||
|
|
||||||
|
assert_equal Time, time.class
|
||||||
|
assert_equal time.object_id, @twz.to_time.object_id
|
||||||
|
assert_equal Time.local(1999, 12, 31, 19), time
|
||||||
|
assert_equal Time.local(1999, 12, 31, 19).utc_offset, time.utc_offset
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@ -518,6 +536,7 @@ def test_freeze_preloads_instance_variables
|
|||||||
@twz.period
|
@twz.period
|
||||||
@twz.time
|
@twz.time
|
||||||
@twz.to_datetime
|
@twz.to_datetime
|
||||||
|
@twz.to_time
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user