activesupport 5.2.4.4 → 6.1.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +353 -435
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +14 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +29 -3
  9. data/lib/active_support/benchmarkable.rb +1 -1
  10. data/lib/active_support/cache.rb +142 -78
  11. data/lib/active_support/cache/file_store.rb +33 -33
  12. data/lib/active_support/cache/mem_cache_store.rb +32 -20
  13. data/lib/active_support/cache/memory_store.rb +59 -33
  14. data/lib/active_support/cache/null_store.rb +8 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +70 -43
  16. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  17. data/lib/active_support/callbacks.rb +81 -64
  18. data/lib/active_support/concern.rb +70 -3
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  20. data/lib/active_support/concurrency/share_lock.rb +0 -1
  21. data/lib/active_support/configurable.rb +10 -14
  22. data/lib/active_support/configuration_file.rb +46 -0
  23. data/lib/active_support/core_ext.rb +1 -1
  24. data/lib/active_support/core_ext/array.rb +1 -1
  25. data/lib/active_support/core_ext/array/access.rb +18 -6
  26. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/benchmark.rb +2 -2
  29. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  30. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  31. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  32. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  36. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  37. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  38. data/lib/active_support/core_ext/enumerable.rb +171 -75
  39. data/lib/active_support/core_ext/hash.rb +1 -2
  40. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  41. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  42. data/lib/active_support/core_ext/hash/except.rb +2 -2
  43. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  44. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  45. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  46. data/lib/active_support/core_ext/kernel.rb +0 -1
  47. data/lib/active_support/core_ext/load_error.rb +1 -1
  48. data/lib/active_support/core_ext/marshal.rb +2 -0
  49. data/lib/active_support/core_ext/module.rb +0 -1
  50. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  51. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  52. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  53. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  54. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  55. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  56. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  57. data/lib/active_support/core_ext/name_error.rb +29 -2
  58. data/lib/active_support/core_ext/numeric.rb +0 -1
  59. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  60. data/lib/active_support/core_ext/object/blank.rb +1 -2
  61. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  62. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  63. data/lib/active_support/core_ext/object/json.rb +14 -2
  64. data/lib/active_support/core_ext/object/try.rb +17 -7
  65. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  66. data/lib/active_support/core_ext/range/compare_range.rb +34 -13
  67. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  68. data/lib/active_support/core_ext/range/each.rb +0 -1
  69. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  70. data/lib/active_support/core_ext/regexp.rb +8 -5
  71. data/lib/active_support/core_ext/securerandom.rb +23 -3
  72. data/lib/active_support/core_ext/string/access.rb +5 -16
  73. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  74. data/lib/active_support/core_ext/string/filters.rb +42 -1
  75. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  76. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  77. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  78. data/lib/active_support/core_ext/string/output_safety.rb +70 -13
  79. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  80. data/lib/active_support/core_ext/string/strip.rb +3 -1
  81. data/lib/active_support/core_ext/symbol.rb +3 -0
  82. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  83. data/lib/active_support/core_ext/time/calculations.rb +50 -3
  84. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  85. data/lib/active_support/core_ext/uri.rb +6 -1
  86. data/lib/active_support/current_attributes.rb +15 -2
  87. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  88. data/lib/active_support/dependencies.rb +109 -34
  89. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  90. data/lib/active_support/deprecation.rb +6 -1
  91. data/lib/active_support/deprecation/behaviors.rb +16 -3
  92. data/lib/active_support/deprecation/disallowed.rb +56 -0
  93. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  94. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  95. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  96. data/lib/active_support/deprecation/reporting.rb +50 -7
  97. data/lib/active_support/descendants_tracker.rb +59 -9
  98. data/lib/active_support/duration.rb +90 -38
  99. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  100. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  101. data/lib/active_support/encrypted_configuration.rb +0 -4
  102. data/lib/active_support/encrypted_file.rb +22 -4
  103. data/lib/active_support/environment_inquirer.rb +20 -0
  104. data/lib/active_support/evented_file_update_checker.rb +82 -117
  105. data/lib/active_support/execution_wrapper.rb +1 -0
  106. data/lib/active_support/file_update_checker.rb +0 -1
  107. data/lib/active_support/fork_tracker.rb +62 -0
  108. data/lib/active_support/gem_version.rb +4 -4
  109. data/lib/active_support/hash_with_indifferent_access.rb +64 -41
  110. data/lib/active_support/i18n.rb +1 -0
  111. data/lib/active_support/i18n_railtie.rb +15 -8
  112. data/lib/active_support/inflector/inflections.rb +2 -7
  113. data/lib/active_support/inflector/methods.rb +49 -58
  114. data/lib/active_support/inflector/transliterate.rb +47 -18
  115. data/lib/active_support/json/decoding.rb +25 -26
  116. data/lib/active_support/json/encoding.rb +11 -3
  117. data/lib/active_support/key_generator.rb +1 -33
  118. data/lib/active_support/lazy_load_hooks.rb +5 -2
  119. data/lib/active_support/locale/en.rb +33 -0
  120. data/lib/active_support/locale/en.yml +7 -3
  121. data/lib/active_support/log_subscriber.rb +39 -9
  122. data/lib/active_support/logger.rb +2 -17
  123. data/lib/active_support/logger_silence.rb +11 -19
  124. data/lib/active_support/logger_thread_safe_level.rb +50 -6
  125. data/lib/active_support/message_encryptor.rb +8 -13
  126. data/lib/active_support/message_verifier.rb +10 -10
  127. data/lib/active_support/messages/metadata.rb +11 -2
  128. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  129. data/lib/active_support/messages/rotator.rb +10 -9
  130. data/lib/active_support/multibyte/chars.rb +10 -68
  131. data/lib/active_support/multibyte/unicode.rb +15 -327
  132. data/lib/active_support/notifications.rb +72 -8
  133. data/lib/active_support/notifications/fanout.rb +116 -16
  134. data/lib/active_support/notifications/instrumenter.rb +71 -9
  135. data/lib/active_support/number_helper.rb +38 -12
  136. data/lib/active_support/number_helper/number_converter.rb +5 -6
  137. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  138. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  139. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  140. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  141. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  142. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  143. data/lib/active_support/number_helper/number_to_rounded_converter.rb +8 -7
  144. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  145. data/lib/active_support/option_merger.rb +22 -3
  146. data/lib/active_support/ordered_hash.rb +1 -1
  147. data/lib/active_support/ordered_options.rb +13 -3
  148. data/lib/active_support/parameter_filter.rb +133 -0
  149. data/lib/active_support/per_thread_registry.rb +1 -1
  150. data/lib/active_support/rails.rb +1 -10
  151. data/lib/active_support/railtie.rb +23 -1
  152. data/lib/active_support/reloader.rb +4 -5
  153. data/lib/active_support/rescuable.rb +4 -4
  154. data/lib/active_support/secure_compare_rotator.rb +51 -0
  155. data/lib/active_support/security_utils.rb +19 -12
  156. data/lib/active_support/string_inquirer.rb +4 -3
  157. data/lib/active_support/subscriber.rb +72 -28
  158. data/lib/active_support/tagged_logging.rb +42 -8
  159. data/lib/active_support/test_case.rb +91 -0
  160. data/lib/active_support/testing/assertions.rb +30 -9
  161. data/lib/active_support/testing/deprecation.rb +0 -1
  162. data/lib/active_support/testing/file_fixtures.rb +2 -0
  163. data/lib/active_support/testing/isolation.rb +2 -2
  164. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  165. data/lib/active_support/testing/parallelization.rb +51 -0
  166. data/lib/active_support/testing/parallelization/server.rb +78 -0
  167. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  168. data/lib/active_support/testing/stream.rb +1 -2
  169. data/lib/active_support/testing/time_helpers.rb +47 -12
  170. data/lib/active_support/time_with_zone.rb +81 -47
  171. data/lib/active_support/values/time_zone.rb +32 -17
  172. data/lib/active_support/xml_mini.rb +2 -10
  173. data/lib/active_support/xml_mini/jdom.rb +2 -3
  174. data/lib/active_support/xml_mini/libxml.rb +2 -2
  175. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  178. data/lib/active_support/xml_mini/rexml.rb +10 -3
  179. metadata +58 -32
  180. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  181. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  182. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  183. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  184. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  185. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  186. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  187. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -4,7 +4,6 @@ module ActiveSupport
4
4
  module Testing
5
5
  module Stream #:nodoc:
6
6
  private
7
-
8
7
  def silence_stream(stream)
9
8
  old_stream = stream.dup
10
9
  stream.reopen(IO::NULL)
@@ -33,7 +32,7 @@ module ActiveSupport
33
32
  yield
34
33
 
35
34
  stream_io.rewind
36
- return captured_stream.read
35
+ captured_stream.read
37
36
  ensure
38
37
  captured_stream.close
39
38
  captured_stream.unlink
@@ -1,12 +1,12 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/module/redefine_method"
4
- require "active_support/core_ext/string/strip" # for strip_heredoc
5
4
  require "active_support/core_ext/time/calculations"
6
5
  require "concurrent/map"
7
6
 
8
7
  module ActiveSupport
9
8
  module Testing
9
+ # Manages stubs for TimeHelpers
10
10
  class SimpleStubs # :nodoc:
11
11
  Stub = Struct.new(:object, :method_name, :original_method)
12
12
 
@@ -14,6 +14,13 @@ module ActiveSupport
14
14
  @stubs = Concurrent::Map.new { |h, k| h[k] = {} }
15
15
  end
16
16
 
17
+ # Stubs object.method_name with the given block
18
+ # If the method is already stubbed, remove that stub
19
+ # so that removing this stub will restore the original implementation.
20
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
21
+ # target = Time.zone.local(2004, 11, 24, 1, 4, 44)
22
+ # simple_stubs.stub_object(Time, :now) { at(target.to_i) }
23
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
17
24
  def stub_object(object, method_name, &block)
18
25
  if stub = stubbing(object, method_name)
19
26
  unstub_object(stub)
@@ -23,10 +30,11 @@ module ActiveSupport
23
30
 
24
31
  @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
25
32
 
26
- object.singleton_class.send :alias_method, new_name, method_name
33
+ object.singleton_class.alias_method new_name, method_name
27
34
  object.define_singleton_method(method_name, &block)
28
35
  end
29
36
 
37
+ # Remove all object-method stubs held by this instance
30
38
  def unstub_all!
31
39
  @stubs.each_value do |object_stubs|
32
40
  object_stubs.each_value do |stub|
@@ -36,17 +44,24 @@ module ActiveSupport
36
44
  @stubs.clear
37
45
  end
38
46
 
47
+ # Returns the Stub for object#method_name
48
+ # (nil if it is not stubbed)
39
49
  def stubbing(object, method_name)
40
50
  @stubs[object.object_id][method_name]
41
51
  end
42
52
 
43
- private
53
+ # Returns true if any stubs are set, false if there are none
54
+ def stubbed?
55
+ !@stubs.empty?
56
+ end
44
57
 
58
+ private
59
+ # Restores the original object.method described by the Stub
45
60
  def unstub_object(stub)
46
61
  singleton_class = stub.object.singleton_class
47
- singleton_class.send :silence_redefinition_of_method, stub.method_name
48
- singleton_class.send :alias_method, stub.method_name, stub.original_method
49
- singleton_class.send :undef_method, stub.original_method
62
+ singleton_class.silence_redefinition_of_method stub.method_name
63
+ singleton_class.alias_method stub.method_name, stub.original_method
64
+ singleton_class.undef_method stub.original_method
50
65
  end
51
66
  end
52
67
 
@@ -84,7 +99,7 @@ module ActiveSupport
84
99
  # The stubs are automatically removed at the end of the test.
85
100
  #
86
101
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
87
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
102
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
88
103
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
89
104
  # Date.current # => Wed, 24 Nov 2004
90
105
  # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
@@ -106,13 +121,13 @@ module ActiveSupport
106
121
  # state at the end of the block:
107
122
  #
108
123
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
109
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do
124
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44) do
110
125
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
111
126
  # end
112
127
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
113
128
  def travel_to(date_or_time)
114
129
  if block_given? && simple_stubs.stubbing(Time, :now)
115
- travel_to_nested_block_call = <<-MSG.strip_heredoc
130
+ travel_to_nested_block_call = <<~MSG
116
131
 
117
132
  Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
118
133
 
@@ -159,16 +174,37 @@ module ActiveSupport
159
174
  end
160
175
 
161
176
  # Returns the current time back to its original state, by removing the stubs added by
162
- # +travel+ and +travel_to+.
177
+ # +travel+, +travel_to+, and +freeze_time+.
163
178
  #
164
179
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
165
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
180
+ #
181
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
166
182
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
183
+ #
167
184
  # travel_back
168
185
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
186
+ #
187
+ # This method also accepts a block, which brings the stubs back at the end of the block:
188
+ #
189
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
190
+ #
191
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
192
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
193
+ #
194
+ # travel_back do
195
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
196
+ # end
197
+ #
198
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
169
199
  def travel_back
200
+ stubbed_time = Time.current if block_given? && simple_stubs.stubbed?
201
+
170
202
  simple_stubs.unstub_all!
203
+ yield if block_given?
204
+ ensure
205
+ travel_to stubbed_time if stubbed_time
171
206
  end
207
+ alias_method :unfreeze_time, :travel_back
172
208
 
173
209
  # Calls +travel_to+ with +Time.now+.
174
210
  #
@@ -191,7 +227,6 @@ module ActiveSupport
191
227
  end
192
228
 
193
229
  private
194
-
195
230
  def simple_stubs
196
231
  @simple_stubs ||= SimpleStubs.new
197
232
  end
@@ -15,25 +15,25 @@ module ActiveSupport
15
15
  # and +in_time_zone+ on Time and DateTime instances.
16
16
  #
17
17
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
18
- # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
19
- # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00
20
- # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
21
- # Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00
22
- # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45 EST -05:00
18
+ # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
19
+ # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
20
+ # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
21
+ # Time.zone.now # => Sun, 18 May 2008 13:07:55.754107581 EDT -04:00
22
+ # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
23
23
  #
24
24
  # See Time and TimeZone for further documentation of these methods.
25
25
  #
26
26
  # TimeWithZone instances implement the same API as Ruby Time instances, so
27
27
  # that Time and TimeWithZone instances are interchangeable.
28
28
  #
29
- # t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
29
+ # t = Time.zone.now # => Sun, 18 May 2008 13:27:25.031505668 EDT -04:00
30
30
  # t.hour # => 13
31
31
  # t.dst? # => true
32
32
  # t.utc_offset # => -14400
33
33
  # t.zone # => "EDT"
34
34
  # t.to_s(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
35
- # t + 1.day # => Mon, 19 May 2008 13:27:25 EDT -04:00
36
- # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00 EST -05:00
35
+ # t + 1.day # => Mon, 19 May 2008 13:27:25.031505668 EDT -04:00
36
+ # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00.000000000 EST -05:00
37
37
  # t > Time.utc(1999) # => true
38
38
  # t.is_a?(Time) # => true
39
39
  # t.is_a?(ActiveSupport::TimeWithZone) # => true
@@ -43,8 +43,8 @@ module ActiveSupport
43
43
  "Time"
44
44
  end
45
45
 
46
- PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N".freeze }
47
- PRECISIONS[0] = "%FT%T".freeze
46
+ PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N" }
47
+ PRECISIONS[0] = "%FT%T"
48
48
 
49
49
  include Comparable, DateAndTime::Compatibility
50
50
  attr_reader :time_zone
@@ -57,12 +57,12 @@ module ActiveSupport
57
57
 
58
58
  # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
59
59
  def time
60
- @time ||= period.to_local(@utc)
60
+ @time ||= incorporate_utc_offset(@utc, utc_offset)
61
61
  end
62
62
 
63
63
  # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
64
64
  def utc
65
- @utc ||= period.to_utc(@time)
65
+ @utc ||= incorporate_utc_offset(@time, -utc_offset)
66
66
  end
67
67
  alias_method :comparable_time, :utc
68
68
  alias_method :getgm, :utc
@@ -104,13 +104,13 @@ module ActiveSupport
104
104
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
105
105
  # Time.zone.now.utc? # => false
106
106
  def utc?
107
- period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
107
+ zone == "UTC" || zone == "UCT"
108
108
  end
109
109
  alias_method :gmt?, :utc?
110
110
 
111
111
  # Returns the offset from current time to UTC time in seconds.
112
112
  def utc_offset
113
- period.utc_total_offset
113
+ period.observed_utc_offset
114
114
  end
115
115
  alias_method :gmt_offset, :utc_offset
116
116
  alias_method :gmtoff, :utc_offset
@@ -132,14 +132,14 @@ module ActiveSupport
132
132
  # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
133
133
  # Time.zone.now.zone # => "EST"
134
134
  def zone
135
- period.zone_identifier.to_s
135
+ period.abbreviation
136
136
  end
137
137
 
138
138
  # Returns a string of the object's date, time, zone, and offset from UTC.
139
139
  #
140
- # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00"
140
+ # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25.624541392 EST -05:00"
141
141
  def inspect
142
- "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
142
+ "#{time.strftime('%a, %d %b %Y %H:%M:%S.%9N')} #{zone} #{formatted_offset}"
143
143
  end
144
144
 
145
145
  # Returns a string of the object's date and time in the ISO 8601 standard
@@ -147,7 +147,7 @@ module ActiveSupport
147
147
  #
148
148
  # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
149
149
  def xmlschema(fraction_digits = 0)
150
- "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z'.freeze)}"
150
+ "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z')}"
151
151
  end
152
152
  alias_method :iso8601, :xmlschema
153
153
  alias_method :rfc3339, :xmlschema
@@ -225,6 +225,8 @@ module ActiveSupport
225
225
  def <=>(other)
226
226
  utc <=> other
227
227
  end
228
+ alias_method :before?, :<
229
+ alias_method :after?, :>
228
230
 
229
231
  # Returns true if the current object's time is within the specified
230
232
  # +min+ and +max+ time.
@@ -243,6 +245,20 @@ module ActiveSupport
243
245
  time.today?
244
246
  end
245
247
 
248
+ # Returns true if the current object's time falls within
249
+ # the next day (tomorrow).
250
+ def tomorrow?
251
+ time.tomorrow?
252
+ end
253
+ alias :next_day? :tomorrow?
254
+
255
+ # Returns true if the current object's time falls within
256
+ # the previous day (yesterday).
257
+ def yesterday?
258
+ time.yesterday?
259
+ end
260
+ alias :prev_day? :yesterday?
261
+
246
262
  # Returns true if the current object's time is in the future.
247
263
  def future?
248
264
  utc.future?
@@ -261,8 +277,8 @@ module ActiveSupport
261
277
  # value as a new TimeWithZone object.
262
278
  #
263
279
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
264
- # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
265
- # now + 1000 # => Sun, 02 Nov 2014 01:43:08 EDT -04:00
280
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
281
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08.725182881 EDT -04:00
266
282
  #
267
283
  # If we're adding a Duration of variable length (i.e., years, months, days),
268
284
  # move forward from #time, otherwise move forward from #utc, for accuracy
@@ -271,8 +287,8 @@ module ActiveSupport
271
287
  # For instance, a time + 24.hours will advance exactly 24 hours, while a
272
288
  # time + 1.day will advance 23-25 hours, depending on the day.
273
289
  #
274
- # now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
275
- # now + 1.day # => Mon, 03 Nov 2014 01:26:28 EST -05:00
290
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
291
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28.725182881 EST -05:00
276
292
  def +(other)
277
293
  if duration_of_variable_length?(other)
278
294
  method_missing(:+, other)
@@ -284,12 +300,14 @@ module ActiveSupport
284
300
  alias_method :since, :+
285
301
  alias_method :in, :+
286
302
 
287
- # Returns a new TimeWithZone object that represents the difference between
288
- # the current object's time and the +other+ time.
303
+ # Subtracts an interval of time and returns a new TimeWithZone object unless
304
+ # the other value `acts_like?` time. Then it will return a Float of the difference
305
+ # between the two times that represents the difference between the current
306
+ # object's time and the +other+ time.
289
307
  #
290
308
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
291
- # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
292
- # now - 1000 # => Mon, 03 Nov 2014 00:09:48 EST -05:00
309
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
310
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
293
311
  #
294
312
  # If subtracting a Duration of variable length (i.e., years, months, days),
295
313
  # move backward from #time, otherwise move backward from #utc, for accuracy
@@ -298,8 +316,14 @@ module ActiveSupport
298
316
  # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
299
317
  # time - 1.day will subtract 23-25 hours, depending on the day.
300
318
  #
301
- # now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
302
- # now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
319
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
320
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
321
+ #
322
+ # If both the TimeWithZone object and the other value act like Time, a Float
323
+ # will be returned.
324
+ #
325
+ # Time.zone.now - 1.day.ago # => 86399.999967
326
+ #
303
327
  def -(other)
304
328
  if other.acts_like?(:time)
305
329
  to_time - other.to_time
@@ -315,8 +339,8 @@ module ActiveSupport
315
339
  # the result as a new TimeWithZone object.
316
340
  #
317
341
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
318
- # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
319
- # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48 EST -05:00
342
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
343
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
320
344
  #
321
345
  # If we're subtracting a Duration of variable length (i.e., years, months,
322
346
  # days), move backward from #time, otherwise move backward from #utc, for
@@ -326,8 +350,8 @@ module ActiveSupport
326
350
  # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
327
351
  # the day.
328
352
  #
329
- # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
330
- # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
353
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
354
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
331
355
  def ago(other)
332
356
  since(-other)
333
357
  end
@@ -343,12 +367,12 @@ module ActiveSupport
343
367
  # or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
344
368
  # <tt>:offset</tt>, not both.
345
369
  #
346
- # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15 EST -05:00
347
- # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15 EST -05:00
348
- # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00 EST -05:00
349
- # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00 EST -05:00
350
- # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
351
- # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
370
+ # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00
371
+ # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15.116992711 EST -05:00
372
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.116992711 EST -05:00
373
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.116992711 EST -05:00
374
+ # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
375
+ # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
352
376
  def change(options)
353
377
  if options[:zone] && options[:offset]
354
378
  raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
@@ -381,14 +405,14 @@ module ActiveSupport
381
405
  # accuracy when moving across DST boundaries.
382
406
  #
383
407
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
384
- # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
385
- # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29 EDT -04:00
386
- # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28 EDT -04:00
387
- # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28 EST -05:00
388
- # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28 EST -05:00
389
- # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28 EST -05:00
390
- # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28 EST -05:00
391
- # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28 EST -05:00
408
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.558049687 EDT -04:00
409
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29.558049687 EDT -04:00
410
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28.558049687 EDT -04:00
411
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28.558049687 EST -05:00
412
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28.558049687 EST -05:00
413
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28.558049687 EST -05:00
414
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28.558049687 EST -05:00
415
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28.558049687 EST -05:00
392
416
  def advance(options)
393
417
  # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
394
418
  # otherwise advance from #utc, for accuracy when moving across DST boundaries
@@ -410,7 +434,7 @@ module ActiveSupport
410
434
  # Returns Array of parts of Time in sequence of
411
435
  # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
412
436
  #
413
- # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
437
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27.485278555 UTC +00:00
414
438
  # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
415
439
  def to_a
416
440
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
@@ -514,6 +538,16 @@ module ActiveSupport
514
538
  end
515
539
 
516
540
  private
541
+ SECONDS_PER_DAY = 86400
542
+
543
+ def incorporate_utc_offset(time, offset)
544
+ if time.kind_of?(Date)
545
+ time + Rational(offset, SECONDS_PER_DAY)
546
+ else
547
+ time + offset
548
+ end
549
+ end
550
+
517
551
  def get_period_and_ensure_valid_local_time(period)
518
552
  # we don't want a Time.local instance enforcing its own DST rules as well,
519
553
  # so transfer time values to a utc constructor if necessary
@@ -2,7 +2,6 @@
2
2
 
3
3
  require "tzinfo"
4
4
  require "concurrent/map"
5
- require "active_support/core_ext/object/blank"
6
5
 
7
6
  module ActiveSupport
8
7
  # The TimeZone class serves as a wrapper around TZInfo::Timezone instances.
@@ -183,8 +182,9 @@ module ActiveSupport
183
182
  "Samoa" => "Pacific/Apia"
184
183
  }
185
184
 
186
- UTC_OFFSET_WITH_COLON = "%s%02d:%02d"
187
- UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(":", "")
185
+ UTC_OFFSET_WITH_COLON = "%s%02d:%02d" # :nodoc:
186
+ UTC_OFFSET_WITHOUT_COLON = UTC_OFFSET_WITH_COLON.tr(":", "") # :nodoc:
187
+ private_constant :UTC_OFFSET_WITH_COLON, :UTC_OFFSET_WITHOUT_COLON
188
188
 
189
189
  @lazy_zones_map = Concurrent::Map.new
190
190
  @country_zones = Concurrent::Map.new
@@ -203,7 +203,7 @@ module ActiveSupport
203
203
  end
204
204
 
205
205
  def find_tzinfo(name)
206
- TZInfo::Timezone.new(MAPPING[name] || name)
206
+ TZInfo::Timezone.get(MAPPING[name] || name)
207
207
  end
208
208
 
209
209
  alias_method :create, :new
@@ -266,16 +266,16 @@ module ActiveSupport
266
266
  private
267
267
  def load_country_zones(code)
268
268
  country = TZInfo::Country.get(code)
269
- country.zone_identifiers.map do |tz_id|
269
+ country.zone_identifiers.flat_map do |tz_id|
270
270
  if MAPPING.value?(tz_id)
271
271
  MAPPING.inject([]) do |memo, (key, value)|
272
272
  memo << self[key] if value == tz_id
273
273
  memo
274
274
  end
275
275
  else
276
- create(tz_id, nil, TZInfo::Timezone.new(tz_id))
276
+ create(tz_id, nil, TZInfo::Timezone.get(tz_id))
277
277
  end
278
- end.flatten(1).sort!
278
+ end.sort!
279
279
  end
280
280
 
281
281
  def zones_map
@@ -302,11 +302,7 @@ module ActiveSupport
302
302
 
303
303
  # Returns the offset of this time zone from UTC in seconds.
304
304
  def utc_offset
305
- if @utc_offset
306
- @utc_offset
307
- else
308
- tzinfo.current_period.utc_offset if tzinfo && tzinfo.current_period
309
- end
305
+ @utc_offset || tzinfo&.current_period&.base_utc_offset
310
306
  end
311
307
 
312
308
  # Returns a formatted string of the offset from UTC, or an alternative
@@ -334,6 +330,13 @@ module ActiveSupport
334
330
  re === name || re === MAPPING[name]
335
331
  end
336
332
 
333
+ # Compare #name and TZInfo identifier to a supplied regexp, returning +true+
334
+ # if a match is found.
335
+ def match?(re)
336
+ (re == name) || (re == MAPPING[name]) ||
337
+ ((Regexp === re) && (re.match?(name) || re.match?(MAPPING[name])))
338
+ end
339
+
337
340
  # Returns a textual representation of this time zone.
338
341
  def to_s
339
342
  "(GMT#{formatted_offset}) #{name}"
@@ -355,8 +358,13 @@ module ActiveSupport
355
358
  # Time.zone = 'Hawaii' # => "Hawaii"
356
359
  # Time.utc(2000).to_f # => 946684800.0
357
360
  # Time.zone.at(946684800.0) # => Fri, 31 Dec 1999 14:00:00 HST -10:00
358
- def at(secs)
359
- Time.at(secs).utc.in_time_zone(self)
361
+ #
362
+ # A second argument can be supplied to specify sub-second precision.
363
+ #
364
+ # Time.zone = 'Hawaii' # => "Hawaii"
365
+ # Time.at(946684800, 123456.789).nsec # => 123456789
366
+ def at(*args)
367
+ Time.at(*args).utc.in_time_zone(self)
360
368
  end
361
369
 
362
370
  # Method for creating new ActiveSupport::TimeWithZone instance in time zone
@@ -495,10 +503,17 @@ module ActiveSupport
495
503
  end
496
504
 
497
505
  # Adjust the given time to the simultaneous time in the time zone
498
- # represented by +self+. Returns a Time.utc() instance -- if you want an
499
- # ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead.
506
+ # represented by +self+. Returns a local time with the appropriate offset
507
+ # -- if you want an ActiveSupport::TimeWithZone instance, use
508
+ # Time#in_time_zone() instead.
509
+ #
510
+ # As of tzinfo 2, utc_to_local returns a Time with a non-zero utc_offset.
511
+ # See the `utc_to_local_returns_utc_offset_times` config for more info.
500
512
  def utc_to_local(time)
501
- tzinfo.utc_to_local(time)
513
+ tzinfo.utc_to_local(time).yield_self do |t|
514
+ ActiveSupport.utc_to_local_returns_utc_offset_times ?
515
+ t : Time.utc(t.year, t.month, t.day, t.hour, t.min, t.sec, t.sec_fraction)
516
+ end
502
517
  end
503
518
 
504
519
  # Adjust the given time to the simultaneous time in UTC. Returns a