mirror of https://github.com/rails/rails
Merge branch 'tzinfo2'
This commit is contained in:
commit
bf34c808f9
|
@ -73,7 +73,7 @@ PATH
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (~> 5.1)
|
minitest (~> 5.1)
|
||||||
tzinfo (~> 1.1)
|
tzinfo (~> 2.0)
|
||||||
zeitwerk (~> 2.2, >= 2.2.2)
|
zeitwerk (~> 2.2, >= 2.2.2)
|
||||||
rails (6.1.0.alpha)
|
rails (6.1.0.alpha)
|
||||||
actioncable (= 6.1.0.alpha)
|
actioncable (= 6.1.0.alpha)
|
||||||
|
@ -489,14 +489,12 @@ GEM
|
||||||
eventmachine (~> 1.0, >= 1.0.4)
|
eventmachine (~> 1.0, >= 1.0.4)
|
||||||
rack (>= 1, < 3)
|
rack (>= 1, < 3)
|
||||||
thor (1.0.1)
|
thor (1.0.1)
|
||||||
thread_safe (0.3.6)
|
|
||||||
thread_safe (0.3.6-java)
|
|
||||||
tilt (2.0.10)
|
tilt (2.0.10)
|
||||||
turbolinks (5.2.1)
|
turbolinks (5.2.1)
|
||||||
turbolinks-source (~> 5.2)
|
turbolinks-source (~> 5.2)
|
||||||
turbolinks-source (5.2.0)
|
turbolinks-source (5.2.0)
|
||||||
tzinfo (1.2.6)
|
tzinfo (2.0.0)
|
||||||
thread_safe (~> 0.1)
|
concurrent-ruby (~> 1.0)
|
||||||
tzinfo-data (1.2019.3)
|
tzinfo-data (1.2019.3)
|
||||||
tzinfo (>= 1.0.0)
|
tzinfo (>= 1.0.0)
|
||||||
uber (0.1.0)
|
uber (0.1.0)
|
||||||
|
|
|
@ -1,3 +1,16 @@
|
||||||
|
* Update to TZInfo v2.0.0.
|
||||||
|
|
||||||
|
This changes the output of `ActiveSupport::TimeZone.utc_to_local`, but
|
||||||
|
can be controlled with the
|
||||||
|
`Rails.application.config.active_support.utc_to_local_returns_utc_offset_times` config.
|
||||||
|
|
||||||
|
New Rails 6.1 apps have it enabled by default, existing apps can upgrade
|
||||||
|
via the config in config/initializers/new_framework_defaults_6_1.rb
|
||||||
|
|
||||||
|
See the `utc_to_local_returns_utc_offset_times` documentation for details.
|
||||||
|
|
||||||
|
*Phil Ross and Jared Beck*
|
||||||
|
|
||||||
* Add Date and Time `#yesterday?` and `#tomorrow?` alongside `#today?`.
|
* Add Date and Time `#yesterday?` and `#tomorrow?` alongside `#today?`.
|
||||||
|
|
||||||
Aliased to `#prev_day?` and `#next_day?` to match the existing `#prev/next_day` methods.
|
Aliased to `#prev_day?` and `#next_day?` to match the existing `#prev/next_day` methods.
|
||||||
|
|
|
@ -34,7 +34,7 @@ Gem::Specification.new do |s|
|
||||||
# https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves
|
# https://edgeguides.rubyonrails.org/security.html#dependency-management-and-cves
|
||||||
|
|
||||||
s.add_dependency "i18n", ">= 1.6", "< 2"
|
s.add_dependency "i18n", ">= 1.6", "< 2"
|
||||||
s.add_dependency "tzinfo", "~> 1.1"
|
s.add_dependency "tzinfo", "~> 2.0"
|
||||||
s.add_dependency "minitest", "~> 5.1"
|
s.add_dependency "minitest", "~> 5.1"
|
||||||
s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
|
s.add_dependency "concurrent-ruby", "~> 1.0", ">= 1.0.2"
|
||||||
s.add_dependency "zeitwerk", "~> 2.2", ">= 2.2.2"
|
s.add_dependency "zeitwerk", "~> 2.2", ">= 2.2.2"
|
||||||
|
|
|
@ -95,6 +95,14 @@ module ActiveSupport
|
||||||
def self.to_time_preserves_timezone=(value)
|
def self.to_time_preserves_timezone=(value)
|
||||||
DateAndTime::Compatibility.preserve_timezone = value
|
DateAndTime::Compatibility.preserve_timezone = value
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.utc_to_local_returns_utc_offset_times
|
||||||
|
DateAndTime::Compatibility.utc_to_local_returns_utc_offset_times
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.utc_to_local_returns_utc_offset_times=(value)
|
||||||
|
DateAndTime::Compatibility.utc_to_local_returns_utc_offset_times = value
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
autoload :I18n, "active_support/i18n"
|
autoload :I18n, "active_support/i18n"
|
||||||
|
|
|
@ -12,5 +12,20 @@ module DateAndTime
|
||||||
# this behavior, but new apps will have an initializer that sets
|
# this behavior, but new apps will have an initializer that sets
|
||||||
# this to true, because the new behavior is preferred.
|
# this to true, because the new behavior is preferred.
|
||||||
mattr_accessor :preserve_timezone, instance_writer: false, default: false
|
mattr_accessor :preserve_timezone, instance_writer: false, default: false
|
||||||
|
|
||||||
|
# Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
|
||||||
|
#
|
||||||
|
# When `true`, it returns local times with an UTC offset, with `false` local
|
||||||
|
# times are returned as UTC.
|
||||||
|
#
|
||||||
|
# # Given this zone:
|
||||||
|
# zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
||||||
|
#
|
||||||
|
# # With `utc_to_local_returns_utc_offset_times = false`, local time is converted to UTC:
|
||||||
|
# zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 UTC
|
||||||
|
#
|
||||||
|
# # With `utc_to_local_returns_utc_offset_times = true`, local time is returned with UTC offset:
|
||||||
|
# zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 -0500
|
||||||
|
mattr_accessor :utc_to_local_returns_utc_offset_times, instance_writer: false, default: false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,12 +57,12 @@ module ActiveSupport
|
||||||
|
|
||||||
# Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
|
# Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
|
||||||
def time
|
def time
|
||||||
@time ||= period.to_local(@utc)
|
@time ||= incorporate_utc_offset(@utc, utc_offset)
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
|
# Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
|
||||||
def utc
|
def utc
|
||||||
@utc ||= period.to_utc(@time)
|
@utc ||= incorporate_utc_offset(@time, -utc_offset)
|
||||||
end
|
end
|
||||||
alias_method :comparable_time, :utc
|
alias_method :comparable_time, :utc
|
||||||
alias_method :getgm, :utc
|
alias_method :getgm, :utc
|
||||||
|
@ -104,13 +104,13 @@ module ActiveSupport
|
||||||
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
|
||||||
# Time.zone.now.utc? # => false
|
# Time.zone.now.utc? # => false
|
||||||
def utc?
|
def utc?
|
||||||
period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
|
zone == "UTC" || zone == "UCT"
|
||||||
end
|
end
|
||||||
alias_method :gmt?, :utc?
|
alias_method :gmt?, :utc?
|
||||||
|
|
||||||
# Returns the offset from current time to UTC time in seconds.
|
# Returns the offset from current time to UTC time in seconds.
|
||||||
def utc_offset
|
def utc_offset
|
||||||
period.utc_total_offset
|
period.observed_utc_offset
|
||||||
end
|
end
|
||||||
alias_method :gmt_offset, :utc_offset
|
alias_method :gmt_offset, :utc_offset
|
||||||
alias_method :gmtoff, :utc_offset
|
alias_method :gmtoff, :utc_offset
|
||||||
|
@ -132,7 +132,7 @@ module ActiveSupport
|
||||||
# Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
|
# Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
|
||||||
# Time.zone.now.zone # => "EST"
|
# Time.zone.now.zone # => "EST"
|
||||||
def zone
|
def zone
|
||||||
period.zone_identifier.to_s
|
period.abbreviation
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a string of the object's date, time, zone, and offset from UTC.
|
# Returns a string of the object's date, time, zone, and offset from UTC.
|
||||||
|
@ -538,6 +538,16 @@ module ActiveSupport
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
SECONDS_PER_DAY = 86400
|
||||||
|
|
||||||
|
def incorporate_utc_offset(time, offset)
|
||||||
|
if time.kind_of?(Date)
|
||||||
|
time + Rational(offset, SECONDS_PER_DAY)
|
||||||
|
else
|
||||||
|
time + offset
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def get_period_and_ensure_valid_local_time(period)
|
def get_period_and_ensure_valid_local_time(period)
|
||||||
# we don't want a Time.local instance enforcing its own DST rules as well,
|
# we don't want a Time.local instance enforcing its own DST rules as well,
|
||||||
# so transfer time values to a utc constructor if necessary
|
# so transfer time values to a utc constructor if necessary
|
||||||
|
|
|
@ -203,7 +203,7 @@ module ActiveSupport
|
||||||
end
|
end
|
||||||
|
|
||||||
def find_tzinfo(name)
|
def find_tzinfo(name)
|
||||||
TZInfo::Timezone.new(MAPPING[name] || name)
|
TZInfo::Timezone.get(MAPPING[name] || name)
|
||||||
end
|
end
|
||||||
|
|
||||||
alias_method :create, :new
|
alias_method :create, :new
|
||||||
|
@ -273,7 +273,7 @@ module ActiveSupport
|
||||||
memo
|
memo
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
create(tz_id, nil, TZInfo::Timezone.new(tz_id))
|
create(tz_id, nil, TZInfo::Timezone.get(tz_id))
|
||||||
end
|
end
|
||||||
end.sort!
|
end.sort!
|
||||||
end
|
end
|
||||||
|
@ -302,11 +302,7 @@ module ActiveSupport
|
||||||
|
|
||||||
# Returns the offset of this time zone from UTC in seconds.
|
# Returns the offset of this time zone from UTC in seconds.
|
||||||
def utc_offset
|
def utc_offset
|
||||||
if @utc_offset
|
@utc_offset || tzinfo&.current_period&.base_utc_offset
|
||||||
@utc_offset
|
|
||||||
else
|
|
||||||
tzinfo.current_period.utc_offset if tzinfo && tzinfo.current_period
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Returns a formatted string of the offset from UTC, or an alternative
|
# Returns a formatted string of the offset from UTC, or an alternative
|
||||||
|
@ -507,10 +503,17 @@ module ActiveSupport
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adjust the given time to the simultaneous time in the time zone
|
# Adjust the given time to the simultaneous time in the time zone
|
||||||
# represented by +self+. Returns a Time.utc() instance -- if you want an
|
# represented by +self+. Returns a local time with the appropriate offset
|
||||||
# ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead.
|
# -- if you want an ActiveSupport::TimeWithZone instance, use
|
||||||
|
# Time#in_time_zone() instead.
|
||||||
|
#
|
||||||
|
# As of tzinfo 2, utc_to_local returns a Time with a non-zero utc_offset.
|
||||||
|
# See the `utc_to_local_returns_utc_offset_times` config for more info.
|
||||||
def utc_to_local(time)
|
def utc_to_local(time)
|
||||||
tzinfo.utc_to_local(time)
|
tzinfo.utc_to_local(time).yield_self do |t|
|
||||||
|
ActiveSupport.utc_to_local_returns_utc_offset_times ?
|
||||||
|
t : Time.utc(t.year, t.month, t.day, t.hour, t.min, t.sec, t.sec_fraction)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Adjust the given time to the simultaneous time in UTC. Returns a
|
# Adjust the given time to the simultaneous time in UTC. Returns a
|
||||||
|
|
|
@ -10,8 +10,15 @@ class TimeZoneTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
def test_utc_to_local
|
def test_utc_to_local
|
||||||
zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
||||||
assert_equal Time.utc(1999, 12, 31, 19), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500
|
|
||||||
assert_equal Time.utc(2000, 6, 30, 20), zone.utc_to_local(Time.utc(2000, 7)) # dst offset -0400
|
with_utc_to_local_returns_utc_offset_times false do
|
||||||
|
assert_equal Time.utc(1999, 12, 31, 19), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500
|
||||||
|
assert_equal Time.utc(2000, 6, 30, 20), zone.utc_to_local(Time.utc(2000, 7)) # dst offset -0400
|
||||||
|
end
|
||||||
|
with_utc_to_local_returns_utc_offset_times true do
|
||||||
|
assert_equal Time.new(1999, 12, 31, 19, 0, 0, -18000), zone.utc_to_local(Time.utc(2000, 1)) # standard offset -0500
|
||||||
|
assert_equal Time.new(2000, 6, 30, 20, 0, 0, -14400), zone.utc_to_local(Time.utc(2000, 7)) # dst offset -0400
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_local_to_utc
|
def test_local_to_utc
|
||||||
|
@ -22,7 +29,7 @@ class TimeZoneTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
def test_period_for_local
|
def test_period_for_local
|
||||||
zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
|
||||||
assert_instance_of TZInfo::TimezonePeriod, zone.period_for_local(Time.utc(2000))
|
assert_kind_of TZInfo::TimezonePeriod, zone.period_for_local(Time.utc(2000))
|
||||||
end
|
end
|
||||||
|
|
||||||
ActiveSupport::TimeZone::MAPPING.each_key do |name|
|
ActiveSupport::TimeZone::MAPPING.each_key do |name|
|
||||||
|
@ -54,7 +61,7 @@ class TimeZoneTest < ActiveSupport::TestCase
|
||||||
|
|
||||||
define_method("test_utc_offset_for_#{name}") do
|
define_method("test_utc_offset_for_#{name}") do
|
||||||
period = zone.tzinfo.current_period
|
period = zone.tzinfo.current_period
|
||||||
assert_equal period.utc_offset, zone.utc_offset
|
assert_equal period.base_utc_offset, zone.utc_offset
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -96,8 +103,15 @@ class TimeZoneTest < ActiveSupport::TestCase
|
||||||
zone = ActiveSupport::TimeZone["America/Montevideo"]
|
zone = ActiveSupport::TimeZone["America/Montevideo"]
|
||||||
assert_equal ActiveSupport::TimeZone, zone.class
|
assert_equal ActiveSupport::TimeZone, zone.class
|
||||||
assert_equal zone.object_id, ActiveSupport::TimeZone["America/Montevideo"].object_id
|
assert_equal zone.object_id, ActiveSupport::TimeZone["America/Montevideo"].object_id
|
||||||
assert_equal Time.utc(2010, 1, 31, 22), zone.utc_to_local(Time.utc(2010, 2)) # daylight saving offset -0200
|
|
||||||
assert_equal Time.utc(2010, 3, 31, 21), zone.utc_to_local(Time.utc(2010, 4)) # standard offset -0300
|
with_utc_to_local_returns_utc_offset_times false do
|
||||||
|
assert_equal Time.utc(2010, 1, 31, 22), zone.utc_to_local(Time.utc(2010, 2)) # daylight saving offset -0200
|
||||||
|
assert_equal Time.utc(2010, 3, 31, 21), zone.utc_to_local(Time.utc(2010, 4)) # standard offset -0300
|
||||||
|
end
|
||||||
|
with_utc_to_local_returns_utc_offset_times true do
|
||||||
|
assert_equal Time.new(2010, 1, 31, 22, 0, 0, -7200), zone.utc_to_local(Time.utc(2010, 2)) # daylight saving offset -0200
|
||||||
|
assert_equal Time.new(2010, 3, 31, 21, 0, 0, -10800), zone.utc_to_local(Time.utc(2010, 4)) # standard offset -0300
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def test_today
|
def test_today
|
||||||
|
|
|
@ -36,4 +36,12 @@ module TimeZoneTestHelpers
|
||||||
ActiveSupport::TimeZone::MAPPING.clear
|
ActiveSupport::TimeZone::MAPPING.clear
|
||||||
ActiveSupport::TimeZone::MAPPING.merge!(old_mappings)
|
ActiveSupport::TimeZone::MAPPING.merge!(old_mappings)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def with_utc_to_local_returns_utc_offset_times(value)
|
||||||
|
old_tzinfo2_format = ActiveSupport.utc_to_local_returns_utc_offset_times
|
||||||
|
ActiveSupport.utc_to_local_returns_utc_offset_times = value
|
||||||
|
yield
|
||||||
|
ensure
|
||||||
|
ActiveSupport.utc_to_local_returns_utc_offset_times = old_tzinfo2_format
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -178,6 +178,10 @@ module Rails
|
||||||
if respond_to?(:action_dispatch)
|
if respond_to?(:action_dispatch)
|
||||||
action_dispatch.cookies_same_site_protection = :lax
|
action_dispatch.cookies_same_site_protection = :lax
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if respond_to?(:active_support)
|
||||||
|
active_support.utc_to_local_returns_utc_offset_times = true
|
||||||
|
end
|
||||||
else
|
else
|
||||||
raise "Unknown version #{target_version.to_s.inspect}"
|
raise "Unknown version #{target_version.to_s.inspect}"
|
||||||
end
|
end
|
||||||
|
|
|
@ -21,3 +21,7 @@
|
||||||
# This change is not backwards compatible with earlier Rails versions.
|
# This change is not backwards compatible with earlier Rails versions.
|
||||||
# It's best enabled when your entire app is migrated and stable on 6.1.
|
# It's best enabled when your entire app is migrated and stable on 6.1.
|
||||||
# Rails.application.config.action_dispatch.cookies_same_site_protection = :lax
|
# Rails.application.config.action_dispatch.cookies_same_site_protection = :lax
|
||||||
|
|
||||||
|
# Specify whether `ActiveSupport::TimeZone.utc_to_local` returns a time with an
|
||||||
|
# UTC offset or a UTC time.
|
||||||
|
# Rails.application.config.active_support.utc_to_local_returns_utc_offset_times = true
|
||||||
|
|
|
@ -2295,6 +2295,15 @@ module ApplicationTests
|
||||||
assert_equal :lax, Rails.application.config.action_dispatch.cookies_same_site_protection
|
assert_equal :lax, Rails.application.config.action_dispatch.cookies_same_site_protection
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test "enables utc_to_local_returns_utc_offset_times by default" do
|
||||||
|
remove_from_config '.*config\.load_defaults.*\n'
|
||||||
|
add_to_config 'config.load_defaults "6.1"'
|
||||||
|
|
||||||
|
app "development"
|
||||||
|
|
||||||
|
assert_equal true, Rails.application.config.active_support.utc_to_local_returns_utc_offset_times
|
||||||
|
end
|
||||||
|
|
||||||
test "ActiveStorage.queues[:analysis] is :active_storage_analysis by default" do
|
test "ActiveStorage.queues[:analysis] is :active_storage_analysis by default" do
|
||||||
app "development"
|
app "development"
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue