activesupport 5.2.4.3 → 7.0.3

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 (228) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +244 -459
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/array_inquirer.rb +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +31 -5
  8. data/lib/active_support/benchmarkable.rb +3 -3
  9. data/lib/active_support/cache/file_store.rb +47 -41
  10. data/lib/active_support/cache/mem_cache_store.rb +151 -40
  11. data/lib/active_support/cache/memory_store.rb +68 -34
  12. data/lib/active_support/cache/null_store.rb +16 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +103 -101
  14. data/lib/active_support/cache/strategy/local_cache.rb +56 -64
  15. data/lib/active_support/cache.rb +333 -116
  16. data/lib/active_support/callbacks.rb +244 -128
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +72 -5
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
  20. data/lib/active_support/concurrency/share_lock.rb +2 -3
  21. data/lib/active_support/configurable.rb +15 -16
  22. data/lib/active_support/configuration_file.rb +51 -0
  23. data/lib/active_support/core_ext/array/access.rb +15 -7
  24. data/lib/active_support/core_ext/array/conversions.rb +18 -17
  25. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  26. data/lib/active_support/core_ext/array/extract.rb +21 -0
  27. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  28. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  29. data/lib/active_support/core_ext/array.rb +2 -1
  30. data/lib/active_support/core_ext/benchmark.rb +2 -2
  31. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  32. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  33. data/lib/active_support/core_ext/class/subclasses.rb +9 -22
  34. data/lib/active_support/core_ext/date/blank.rb +1 -1
  35. data/lib/active_support/core_ext/date/calculations.rb +15 -14
  36. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  37. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  38. data/lib/active_support/core_ext/date.rb +1 -0
  39. data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -51
  40. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  41. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  42. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  43. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  44. data/lib/active_support/core_ext/date_time/conversions.rb +13 -14
  45. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  46. data/lib/active_support/core_ext/date_time.rb +1 -0
  47. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  48. data/lib/active_support/core_ext/enumerable.rb +241 -76
  49. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  50. data/lib/active_support/core_ext/hash/conversions.rb +3 -4
  51. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  52. data/lib/active_support/core_ext/hash/except.rb +2 -2
  53. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  54. data/lib/active_support/core_ext/hash/keys.rb +2 -31
  55. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  56. data/lib/active_support/core_ext/hash.rb +1 -2
  57. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  58. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  59. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  60. data/lib/active_support/core_ext/kernel.rb +0 -1
  61. data/lib/active_support/core_ext/load_error.rb +1 -1
  62. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  63. data/lib/active_support/core_ext/module/attribute_accessors.rb +32 -39
  64. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +35 -28
  65. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  66. data/lib/active_support/core_ext/module/delegation.rb +70 -33
  67. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  68. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  69. data/lib/active_support/core_ext/module.rb +0 -1
  70. data/lib/active_support/core_ext/name_error.rb +23 -2
  71. data/lib/active_support/core_ext/numeric/conversions.rb +132 -129
  72. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  73. data/lib/active_support/core_ext/numeric.rb +1 -1
  74. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  75. data/lib/active_support/core_ext/object/blank.rb +3 -4
  76. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  77. data/lib/active_support/core_ext/object/duplicable.rb +14 -110
  78. data/lib/active_support/core_ext/object/json.rb +44 -27
  79. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  80. data/lib/active_support/core_ext/object/try.rb +24 -14
  81. data/lib/active_support/core_ext/object/with_options.rb +21 -2
  82. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  83. data/lib/active_support/core_ext/pathname.rb +3 -0
  84. data/lib/active_support/core_ext/range/compare_range.rb +23 -27
  85. data/lib/active_support/core_ext/range/conversions.rb +32 -30
  86. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  87. data/lib/active_support/core_ext/range/each.rb +1 -2
  88. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
  89. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  90. data/lib/active_support/core_ext/range.rb +1 -1
  91. data/lib/active_support/core_ext/regexp.rb +8 -5
  92. data/lib/active_support/core_ext/securerandom.rb +23 -3
  93. data/lib/active_support/core_ext/string/access.rb +5 -16
  94. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  95. data/lib/active_support/core_ext/string/filters.rb +42 -1
  96. data/lib/active_support/core_ext/string/inflections.rb +46 -7
  97. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  98. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  99. data/lib/active_support/core_ext/string/output_safety.rb +129 -20
  100. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  101. data/lib/active_support/core_ext/string/strip.rb +3 -1
  102. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  103. data/lib/active_support/core_ext/symbol.rb +3 -0
  104. data/lib/active_support/core_ext/time/calculations.rb +59 -10
  105. data/lib/active_support/core_ext/time/conversions.rb +15 -12
  106. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  107. data/lib/active_support/core_ext/time/zones.rb +7 -22
  108. data/lib/active_support/core_ext/time.rb +1 -0
  109. data/lib/active_support/core_ext/uri.rb +3 -22
  110. data/lib/active_support/core_ext.rb +2 -1
  111. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  112. data/lib/active_support/current_attributes.rb +47 -16
  113. data/lib/active_support/dependencies/interlock.rb +10 -18
  114. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  115. data/lib/active_support/dependencies.rb +60 -715
  116. data/lib/active_support/deprecation/behaviors.rb +21 -5
  117. data/lib/active_support/deprecation/disallowed.rb +56 -0
  118. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  119. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +31 -8
  121. data/lib/active_support/deprecation/reporting.rb +50 -7
  122. data/lib/active_support/deprecation.rb +7 -2
  123. data/lib/active_support/descendants_tracker.rb +190 -34
  124. data/lib/active_support/digest.rb +5 -3
  125. data/lib/active_support/duration/iso8601_parser.rb +5 -7
  126. data/lib/active_support/duration/iso8601_serializer.rb +27 -15
  127. data/lib/active_support/duration.rb +149 -67
  128. data/lib/active_support/encrypted_configuration.rb +12 -5
  129. data/lib/active_support/encrypted_file.rb +23 -5
  130. data/lib/active_support/environment_inquirer.rb +20 -0
  131. data/lib/active_support/error_reporter.rb +117 -0
  132. data/lib/active_support/evented_file_update_checker.rb +85 -122
  133. data/lib/active_support/execution_context/test_helper.rb +13 -0
  134. data/lib/active_support/execution_context.rb +53 -0
  135. data/lib/active_support/execution_wrapper.rb +44 -21
  136. data/lib/active_support/executor/test_helper.rb +7 -0
  137. data/lib/active_support/file_update_checker.rb +0 -1
  138. data/lib/active_support/fork_tracker.rb +71 -0
  139. data/lib/active_support/gem_version.rb +5 -5
  140. data/lib/active_support/hash_with_indifferent_access.rb +73 -43
  141. data/lib/active_support/html_safe_translation.rb +43 -0
  142. data/lib/active_support/i18n.rb +2 -0
  143. data/lib/active_support/i18n_railtie.rb +15 -8
  144. data/lib/active_support/inflector/inflections.rb +25 -14
  145. data/lib/active_support/inflector/methods.rb +38 -71
  146. data/lib/active_support/inflector/transliterate.rb +47 -18
  147. data/lib/active_support/isolated_execution_state.rb +72 -0
  148. data/lib/active_support/json/decoding.rb +25 -26
  149. data/lib/active_support/json/encoding.rb +14 -6
  150. data/lib/active_support/key_generator.rb +23 -38
  151. data/lib/active_support/lazy_load_hooks.rb +19 -5
  152. data/lib/active_support/locale/en.rb +33 -0
  153. data/lib/active_support/locale/en.yml +8 -4
  154. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  155. data/lib/active_support/log_subscriber.rb +51 -11
  156. data/lib/active_support/logger.rb +6 -22
  157. data/lib/active_support/logger_silence.rb +11 -19
  158. data/lib/active_support/logger_thread_safe_level.rb +45 -10
  159. data/lib/active_support/message_encryptor.rb +20 -19
  160. data/lib/active_support/message_verifier.rb +53 -21
  161. data/lib/active_support/messages/metadata.rb +13 -4
  162. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  163. data/lib/active_support/messages/rotator.rb +10 -9
  164. data/lib/active_support/multibyte/chars.rb +17 -76
  165. data/lib/active_support/multibyte/unicode.rb +7 -331
  166. data/lib/active_support/multibyte.rb +1 -1
  167. data/lib/active_support/notifications/fanout.rb +163 -37
  168. data/lib/active_support/notifications/instrumenter.rb +90 -11
  169. data/lib/active_support/notifications.rb +88 -30
  170. data/lib/active_support/number_helper/number_converter.rb +6 -9
  171. data/lib/active_support/number_helper/number_to_currency_converter.rb +12 -12
  172. data/lib/active_support/number_helper/number_to_delimited_converter.rb +4 -3
  173. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  174. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -4
  175. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  176. data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -2
  177. data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
  178. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  179. data/lib/active_support/number_helper.rb +36 -12
  180. data/lib/active_support/option_merger.rb +15 -4
  181. data/lib/active_support/ordered_hash.rb +2 -2
  182. data/lib/active_support/ordered_options.rb +14 -4
  183. data/lib/active_support/parameter_filter.rb +138 -0
  184. data/lib/active_support/per_thread_registry.rb +6 -1
  185. data/lib/active_support/rails.rb +1 -10
  186. data/lib/active_support/railtie.rb +77 -5
  187. data/lib/active_support/reloader.rb +5 -6
  188. data/lib/active_support/rescuable.rb +8 -8
  189. data/lib/active_support/ruby_features.rb +7 -0
  190. data/lib/active_support/secure_compare_rotator.rb +51 -0
  191. data/lib/active_support/security_utils.rb +19 -12
  192. data/lib/active_support/string_inquirer.rb +2 -3
  193. data/lib/active_support/subscriber.rb +79 -46
  194. data/lib/active_support/tagged_logging.rb +58 -9
  195. data/lib/active_support/test_case.rb +79 -0
  196. data/lib/active_support/testing/assertions.rb +62 -11
  197. data/lib/active_support/testing/deprecation.rb +52 -2
  198. data/lib/active_support/testing/file_fixtures.rb +2 -0
  199. data/lib/active_support/testing/isolation.rb +4 -4
  200. data/lib/active_support/testing/method_call_assertions.rb +32 -5
  201. data/lib/active_support/testing/parallelization/server.rb +82 -0
  202. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  203. data/lib/active_support/testing/parallelization.rb +55 -0
  204. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  205. data/lib/active_support/testing/stream.rb +4 -7
  206. data/lib/active_support/testing/tagged_logging.rb +1 -1
  207. data/lib/active_support/testing/time_helpers.rb +60 -14
  208. data/lib/active_support/time_with_zone.rb +139 -64
  209. data/lib/active_support/values/time_zone.rb +66 -30
  210. data/lib/active_support/version.rb +1 -1
  211. data/lib/active_support/xml_mini/jdom.rb +3 -4
  212. data/lib/active_support/xml_mini/libxml.rb +7 -7
  213. data/lib/active_support/xml_mini/libxmlsax.rb +5 -5
  214. data/lib/active_support/xml_mini/nokogiri.rb +6 -6
  215. data/lib/active_support/xml_mini/nokogirisax.rb +4 -4
  216. data/lib/active_support/xml_mini/rexml.rb +11 -4
  217. data/lib/active_support/xml_mini.rb +7 -14
  218. data/lib/active_support.rb +30 -1
  219. metadata +64 -35
  220. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  221. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  222. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  223. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  224. data/lib/active_support/core_ext/marshal.rb +0 -24
  225. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  226. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  227. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  228. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "yaml"
4
+
3
5
  require "active_support/duration"
4
6
  require "active_support/values/time_zone"
5
7
  require "active_support/core_ext/object/acts_like"
@@ -11,40 +13,47 @@ module ActiveSupport
11
13
  # system's <tt>ENV['TZ']</tt> zone.
12
14
  #
13
15
  # You shouldn't ever need to create a TimeWithZone instance directly via +new+.
14
- # Instead use methods +local+, +parse+, +at+ and +now+ on TimeZone instances,
16
+ # Instead use methods +local+, +parse+, +at+, and +now+ on TimeZone instances,
15
17
  # and +in_time_zone+ on Time and DateTime instances.
16
18
  #
17
19
  # 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
20
+ # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
21
+ # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
22
+ # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
23
+ # Time.zone.now # => Sun, 18 May 2008 13:07:55.754107581 EDT -04:00
24
+ # Time.utc(2007, 2, 10, 20, 30, 45).in_time_zone # => Sat, 10 Feb 2007 15:30:45.000000000 EST -05:00
23
25
  #
24
26
  # See Time and TimeZone for further documentation of these methods.
25
27
  #
26
28
  # TimeWithZone instances implement the same API as Ruby Time instances, so
27
29
  # that Time and TimeWithZone instances are interchangeable.
28
30
  #
29
- # t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
31
+ # t = Time.zone.now # => Sun, 18 May 2008 13:27:25.031505668 EDT -04:00
30
32
  # t.hour # => 13
31
33
  # t.dst? # => true
32
34
  # t.utc_offset # => -14400
33
35
  # t.zone # => "EDT"
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
36
+ # t.to_fs(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
37
+ # t + 1.day # => Mon, 19 May 2008 13:27:25.031505668 EDT -04:00
38
+ # t.beginning_of_year # => Tue, 01 Jan 2008 00:00:00.000000000 EST -05:00
37
39
  # t > Time.utc(1999) # => true
38
40
  # t.is_a?(Time) # => true
39
41
  # t.is_a?(ActiveSupport::TimeWithZone) # => true
40
42
  class TimeWithZone
41
43
  # Report class name as 'Time' to thwart type checking.
42
44
  def self.name
45
+ ActiveSupport::Deprecation.warn(<<~EOM)
46
+ ActiveSupport::TimeWithZone.name has been deprecated and
47
+ from Rails 7.1 will use the default Ruby implementation.
48
+ You can set `config.active_support.remove_deprecated_time_with_zone_name = true`
49
+ to enable the new behavior now.
50
+ EOM
51
+
43
52
  "Time"
44
53
  end
45
54
 
46
- PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N".freeze }
47
- PRECISIONS[0] = "%FT%T".freeze
55
+ PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N" }
56
+ PRECISIONS[0] = "%FT%T"
48
57
 
49
58
  include Comparable, DateAndTime::Compatibility
50
59
  attr_reader :time_zone
@@ -57,19 +66,19 @@ module ActiveSupport
57
66
 
58
67
  # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
59
68
  def time
60
- @time ||= period.to_local(@utc)
69
+ @time ||= incorporate_utc_offset(@utc, utc_offset)
61
70
  end
62
71
 
63
72
  # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
64
73
  def utc
65
- @utc ||= period.to_utc(@time)
74
+ @utc ||= incorporate_utc_offset(@time, -utc_offset)
66
75
  end
67
76
  alias_method :comparable_time, :utc
68
77
  alias_method :getgm, :utc
69
78
  alias_method :getutc, :utc
70
79
  alias_method :gmtime, :utc
71
80
 
72
- # Returns the underlying TZInfo::TimezonePeriod.
81
+ # Returns the underlying <tt>TZInfo::TimezonePeriod</tt>.
73
82
  def period
74
83
  @period ||= time_zone.period_for_utc(@utc)
75
84
  end
@@ -104,13 +113,13 @@ module ActiveSupport
104
113
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
105
114
  # Time.zone.now.utc? # => false
106
115
  def utc?
107
- period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
116
+ zone == "UTC" || zone == "UCT"
108
117
  end
109
118
  alias_method :gmt?, :utc?
110
119
 
111
120
  # Returns the offset from current time to UTC time in seconds.
112
121
  def utc_offset
113
- period.utc_total_offset
122
+ period.observed_utc_offset
114
123
  end
115
124
  alias_method :gmt_offset, :utc_offset
116
125
  alias_method :gmtoff, :utc_offset
@@ -132,14 +141,14 @@ module ActiveSupport
132
141
  # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
133
142
  # Time.zone.now.zone # => "EST"
134
143
  def zone
135
- period.zone_identifier.to_s
144
+ period.abbreviation
136
145
  end
137
146
 
138
147
  # Returns a string of the object's date, time, zone, and offset from UTC.
139
148
  #
140
- # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00"
149
+ # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25.624541392 EST -05:00"
141
150
  def inspect
142
- "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
151
+ "#{time.strftime('%a, %d %b %Y %H:%M:%S.%9N')} #{zone} #{formatted_offset}"
143
152
  end
144
153
 
145
154
  # Returns a string of the object's date and time in the ISO 8601 standard
@@ -147,7 +156,7 @@ module ActiveSupport
147
156
  #
148
157
  # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
149
158
  def xmlschema(fraction_digits = 0)
150
- "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z'.freeze)}"
159
+ "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z')}"
151
160
  end
152
161
  alias_method :iso8601, :xmlschema
153
162
  alias_method :rfc3339, :xmlschema
@@ -172,12 +181,11 @@ module ActiveSupport
172
181
  end
173
182
  end
174
183
 
175
- def init_with(coder) #:nodoc:
184
+ def init_with(coder) # :nodoc:
176
185
  initialize(coder["utc"], coder["zone"], coder["time"])
177
186
  end
178
187
 
179
- def encode_with(coder) #:nodoc:
180
- coder.tag = "!ruby/object:ActiveSupport::TimeWithZone"
188
+ def encode_with(coder) # :nodoc:
181
189
  coder.map = { "utc" => utc, "zone" => time_zone, "time" => time }
182
190
  end
183
191
 
@@ -194,25 +202,53 @@ module ActiveSupport
194
202
  #
195
203
  # Time.zone.now.rfc2822 # => "Tue, 01 Jan 2013 04:51:39 +0000"
196
204
  def rfc2822
197
- to_s(:rfc822)
205
+ to_fs(:rfc822)
198
206
  end
199
207
  alias_method :rfc822, :rfc2822
200
208
 
209
+ NOT_SET = Object.new # :nodoc:
210
+
211
+ # Returns a string of the object's date and time.
212
+ def to_s(format = NOT_SET)
213
+ if format == :db
214
+ ActiveSupport::Deprecation.warn(
215
+ "TimeWithZone#to_s(:db) is deprecated. Please use TimeWithZone#to_fs(:db) instead."
216
+ )
217
+ utc.to_fs(format)
218
+ elsif formatter = ::Time::DATE_FORMATS[format]
219
+ ActiveSupport::Deprecation.warn(
220
+ "TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
221
+ )
222
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
223
+ elsif format == NOT_SET
224
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
225
+ else
226
+ ActiveSupport::Deprecation.warn(
227
+ "TimeWithZone#to_s(#{format.inspect}) is deprecated. Please use TimeWithZone#to_fs(#{format.inspect}) instead."
228
+ )
229
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
230
+ end
231
+ end
232
+
201
233
  # Returns a string of the object's date and time.
234
+ #
235
+ # This method is aliased to <tt>to_formatted_s</tt>.
236
+ #
202
237
  # Accepts an optional <tt>format</tt>:
203
238
  # * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
204
- # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_formatted_s(:db).
239
+ # * <tt>:db</tt> - format outputs time in UTC :db time. See Time#to_fs(:db).
205
240
  # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
206
- def to_s(format = :default)
241
+ def to_fs(format = :default)
207
242
  if format == :db
208
- utc.to_s(format)
243
+ utc.to_fs(format)
209
244
  elsif formatter = ::Time::DATE_FORMATS[format]
210
245
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
211
246
  else
212
- "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
247
+ # Change to to_s when deprecation is gone.
248
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}"
213
249
  end
214
250
  end
215
- alias_method :to_formatted_s, :to_s
251
+ alias_method :to_formatted_s, :to_fs
216
252
 
217
253
  # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
218
254
  # so that zone information is correct.
@@ -225,6 +261,8 @@ module ActiveSupport
225
261
  def <=>(other)
226
262
  utc <=> other
227
263
  end
264
+ alias_method :before?, :<
265
+ alias_method :after?, :>
228
266
 
229
267
  # Returns true if the current object's time is within the specified
230
268
  # +min+ and +max+ time.
@@ -243,6 +281,20 @@ module ActiveSupport
243
281
  time.today?
244
282
  end
245
283
 
284
+ # Returns true if the current object's time falls within
285
+ # the next day (tomorrow).
286
+ def tomorrow?
287
+ time.tomorrow?
288
+ end
289
+ alias :next_day? :tomorrow?
290
+
291
+ # Returns true if the current object's time falls within
292
+ # the previous day (yesterday).
293
+ def yesterday?
294
+ time.yesterday?
295
+ end
296
+ alias :prev_day? :yesterday?
297
+
246
298
  # Returns true if the current object's time is in the future.
247
299
  def future?
248
300
  utc.future?
@@ -261,8 +313,8 @@ module ActiveSupport
261
313
  # value as a new TimeWithZone object.
262
314
  #
263
315
  # 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
316
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
317
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08.725182881 EDT -04:00
266
318
  #
267
319
  # If we're adding a Duration of variable length (i.e., years, months, days),
268
320
  # move forward from #time, otherwise move forward from #utc, for accuracy
@@ -271,8 +323,8 @@ module ActiveSupport
271
323
  # For instance, a time + 24.hours will advance exactly 24 hours, while a
272
324
  # time + 1.day will advance 23-25 hours, depending on the day.
273
325
  #
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
326
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
327
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28.725182881 EST -05:00
276
328
  def +(other)
277
329
  if duration_of_variable_length?(other)
278
330
  method_missing(:+, other)
@@ -284,12 +336,14 @@ module ActiveSupport
284
336
  alias_method :since, :+
285
337
  alias_method :in, :+
286
338
 
287
- # Returns a new TimeWithZone object that represents the difference between
288
- # the current object's time and the +other+ time.
339
+ # Subtracts an interval of time and returns a new TimeWithZone object unless
340
+ # the other value +acts_like?+ time. Then it will return a Float of the difference
341
+ # between the two times that represents the difference between the current
342
+ # object's time and the +other+ time.
289
343
  #
290
344
  # 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
345
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
346
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
293
347
  #
294
348
  # If subtracting a Duration of variable length (i.e., years, months, days),
295
349
  # move backward from #time, otherwise move backward from #utc, for accuracy
@@ -298,8 +352,14 @@ module ActiveSupport
298
352
  # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
299
353
  # time - 1.day will subtract 23-25 hours, depending on the day.
300
354
  #
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
355
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
356
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
357
+ #
358
+ # If both the TimeWithZone object and the other value act like Time, a Float
359
+ # will be returned.
360
+ #
361
+ # Time.zone.now - 1.day.ago # => 86399.999967
362
+ #
303
363
  def -(other)
304
364
  if other.acts_like?(:time)
305
365
  to_time - other.to_time
@@ -315,8 +375,8 @@ module ActiveSupport
315
375
  # the result as a new TimeWithZone object.
316
376
  #
317
377
  # 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
378
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
379
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
320
380
  #
321
381
  # If we're subtracting a Duration of variable length (i.e., years, months,
322
382
  # days), move backward from #time, otherwise move backward from #utc, for
@@ -326,8 +386,8 @@ module ActiveSupport
326
386
  # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
327
387
  # the day.
328
388
  #
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
389
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
390
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
331
391
  def ago(other)
332
392
  since(-other)
333
393
  end
@@ -335,20 +395,20 @@ module ActiveSupport
335
395
  # Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
336
396
  # been changed according to the +options+ parameter. The time options (<tt>:hour</tt>,
337
397
  # <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly,
338
- # so if only the hour is passed, then minute, sec, usec and nsec is set to 0. If the
339
- # hour and minute is passed, then sec, usec and nsec is set to 0. The +options+
398
+ # so if only the hour is passed, then minute, sec, usec, and nsec is set to 0. If the
399
+ # hour and minute is passed, then sec, usec, and nsec is set to 0. The +options+
340
400
  # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
341
401
  # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>,
342
402
  # <tt>:nsec</tt>, <tt>:offset</tt>, <tt>:zone</tt>. Pass either <tt>:usec</tt>
343
403
  # or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
344
404
  # <tt>:offset</tt>, not both.
345
405
  #
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
406
+ # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00
407
+ # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15.116992711 EST -05:00
408
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.116992711 EST -05:00
409
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.116992711 EST -05:00
410
+ # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
411
+ # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
352
412
  def change(options)
353
413
  if options[:zone] && options[:offset]
354
414
  raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
@@ -381,14 +441,14 @@ module ActiveSupport
381
441
  # accuracy when moving across DST boundaries.
382
442
  #
383
443
  # 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
444
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.558049687 EDT -04:00
445
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29.558049687 EDT -04:00
446
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28.558049687 EDT -04:00
447
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28.558049687 EST -05:00
448
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28.558049687 EST -05:00
449
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28.558049687 EST -05:00
450
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28.558049687 EST -05:00
451
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28.558049687 EST -05:00
392
452
  def advance(options)
393
453
  # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
394
454
  # otherwise advance from #utc, for accuracy when moving across DST boundaries
@@ -410,13 +470,13 @@ module ActiveSupport
410
470
  # Returns Array of parts of Time in sequence of
411
471
  # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
412
472
  #
413
- # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
473
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27.485278555 UTC +00:00
414
474
  # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
415
475
  def to_a
416
476
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
417
477
  end
418
478
 
419
- # Returns the object's date and time as a floating point number of seconds
479
+ # Returns the object's date and time as a floating-point number of seconds
420
480
  # since the Epoch (January 1, 1970 00:00 UTC).
421
481
  #
422
482
  # Time.zone.now.to_f # => 1417709320.285418
@@ -510,10 +570,20 @@ module ActiveSupport
510
570
  def method_missing(sym, *args, &block)
511
571
  wrap_with_time_zone time.__send__(sym, *args, &block)
512
572
  rescue NoMethodError => e
513
- raise e, e.message.sub(time.inspect, inspect), e.backtrace
573
+ raise e, e.message.sub(time.inspect, inspect).sub("Time", "ActiveSupport::TimeWithZone"), e.backtrace
514
574
  end
515
575
 
516
576
  private
577
+ SECONDS_PER_DAY = 86400
578
+
579
+ def incorporate_utc_offset(time, offset)
580
+ if time.kind_of?(Date)
581
+ time + Rational(offset, SECONDS_PER_DAY)
582
+ else
583
+ time + offset
584
+ end
585
+ end
586
+
517
587
  def get_period_and_ensure_valid_local_time(period)
518
588
  # we don't want a Time.local instance enforcing its own DST rules as well,
519
589
  # so transfer time values to a utc constructor if necessary
@@ -534,7 +604,7 @@ module ActiveSupport
534
604
  end
535
605
 
536
606
  def duration_of_variable_length?(obj)
537
- ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) }
607
+ ActiveSupport::Duration === obj && obj.variable?
538
608
  end
539
609
 
540
610
  def wrap_with_time_zone(time)
@@ -549,3 +619,8 @@ module ActiveSupport
549
619
  end
550
620
  end
551
621
  end
622
+
623
+ # These prevent Psych from calling `ActiveSupport::TimeWithZone.name`
624
+ # and triggering the deprecation warning about the change in Rails 7.1.
625
+ YAML.load_tags["!ruby/object:ActiveSupport::TimeWithZone"] = "ActiveSupport::TimeWithZone"
626
+ YAML.dump_tags[ActiveSupport::TimeWithZone] = "!ruby/object:ActiveSupport::TimeWithZone"
@@ -2,19 +2,18 @@
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
- # The TimeZone class serves as a wrapper around TZInfo::Timezone instances.
7
+ # The TimeZone class serves as a wrapper around <tt>TZInfo::Timezone</tt> instances.
9
8
  # It allows us to do the following:
10
9
  #
11
10
  # * Limit the set of zones provided by TZInfo to a meaningful subset of 134
12
11
  # zones.
13
12
  # * Retrieve and display zones with a friendlier name
14
13
  # (e.g., "Eastern Time (US & Canada)" instead of "America/New_York").
15
- # * Lazily load TZInfo::Timezone instances only when they're needed.
14
+ # * Lazily load <tt>TZInfo::Timezone</tt> instances only when they're needed.
16
15
  # * Create ActiveSupport::TimeWithZone instances via TimeZone's +local+,
17
- # +parse+, +at+ and +now+ methods.
16
+ # +parse+, +at+, and +now+ methods.
18
17
  #
19
18
  # If you set <tt>config.time_zone</tt> in the Rails Application, you can
20
19
  # access this TimeZone object via <tt>Time.zone</tt>:
@@ -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
@@ -229,12 +229,16 @@ module ActiveSupport
229
229
  # Returns +nil+ if no such time zone is known to the system.
230
230
  def [](arg)
231
231
  case arg
232
+ when self
233
+ arg
232
234
  when String
233
235
  begin
234
236
  @lazy_zones_map[arg] ||= create(arg)
235
237
  rescue TZInfo::InvalidTimezoneIdentifier
236
238
  nil
237
239
  end
240
+ when TZInfo::Timezone
241
+ @lazy_zones_map[arg.name] ||= create(arg.name, nil, arg)
238
242
  when Numeric, ActiveSupport::Duration
239
243
  arg *= 3600 if arg.abs <= 13
240
244
  all.find { |z| z.utc_offset == arg.to_i }
@@ -256,7 +260,7 @@ module ActiveSupport
256
260
  @country_zones[code] ||= load_country_zones(code)
257
261
  end
258
262
 
259
- def clear #:nodoc:
263
+ def clear # :nodoc:
260
264
  @lazy_zones_map = Concurrent::Map.new
261
265
  @country_zones = Concurrent::Map.new
262
266
  @zones = nil
@@ -266,16 +270,16 @@ module ActiveSupport
266
270
  private
267
271
  def load_country_zones(code)
268
272
  country = TZInfo::Country.get(code)
269
- country.zone_identifiers.map do |tz_id|
273
+ country.zone_identifiers.flat_map do |tz_id|
270
274
  if MAPPING.value?(tz_id)
271
275
  MAPPING.inject([]) do |memo, (key, value)|
272
276
  memo << self[key] if value == tz_id
273
277
  memo
274
278
  end
275
279
  else
276
- create(tz_id, nil, TZInfo::Timezone.new(tz_id))
280
+ create(tz_id, nil, TZInfo::Timezone.get(tz_id))
277
281
  end
278
- end.flatten(1).sort!
282
+ end.sort!
279
283
  end
280
284
 
281
285
  def zones_map
@@ -302,11 +306,7 @@ module ActiveSupport
302
306
 
303
307
  # Returns the offset of this time zone from UTC in seconds.
304
308
  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
309
+ @utc_offset || tzinfo&.current_period&.base_utc_offset
310
310
  end
311
311
 
312
312
  # Returns a formatted string of the offset from UTC, or an alternative
@@ -334,6 +334,13 @@ module ActiveSupport
334
334
  re === name || re === MAPPING[name]
335
335
  end
336
336
 
337
+ # Compare #name and TZInfo identifier to a supplied regexp, returning +true+
338
+ # if a match is found.
339
+ def match?(re)
340
+ (re == name) || (re == MAPPING[name]) ||
341
+ ((Regexp === re) && (re.match?(name) || re.match?(MAPPING[name])))
342
+ end
343
+
337
344
  # Returns a textual representation of this time zone.
338
345
  def to_s
339
346
  "(GMT#{formatted_offset}) #{name}"
@@ -355,8 +362,13 @@ module ActiveSupport
355
362
  # Time.zone = 'Hawaii' # => "Hawaii"
356
363
  # Time.utc(2000).to_f # => 946684800.0
357
364
  # 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)
365
+ #
366
+ # A second argument can be supplied to specify sub-second precision.
367
+ #
368
+ # Time.zone = 'Hawaii' # => "Hawaii"
369
+ # Time.at(946684800, 123456.789).nsec # => 123456789
370
+ def at(*args)
371
+ Time.at(*args).utc.in_time_zone(self)
360
372
  end
361
373
 
362
374
  # Method for creating new ActiveSupport::TimeWithZone instance in time zone
@@ -373,14 +385,28 @@ module ActiveSupport
373
385
  # If the string is invalid then an +ArgumentError+ will be raised unlike +parse+
374
386
  # which usually returns +nil+ when given an invalid date string.
375
387
  def iso8601(str)
388
+ # Historically `Date._iso8601(nil)` returns `{}`, but in the `date` gem versions `3.2.1`, `3.1.2`, `3.0.2`,
389
+ # and `2.0.1`, `Date._iso8601(nil)` raises `TypeError` https://github.com/ruby/date/issues/39
390
+ # Future `date` releases are expected to revert back to the original behavior.
391
+ raise ArgumentError, "invalid date" if str.nil?
392
+
376
393
  parts = Date._iso8601(str)
377
394
 
378
- raise ArgumentError, "invalid date" if parts.empty?
395
+ year = parts.fetch(:year)
396
+
397
+ if parts.key?(:yday)
398
+ ordinal_date = Date.ordinal(year, parts.fetch(:yday))
399
+ month = ordinal_date.month
400
+ day = ordinal_date.day
401
+ else
402
+ month = parts.fetch(:mon)
403
+ day = parts.fetch(:mday)
404
+ end
379
405
 
380
406
  time = Time.new(
381
- parts.fetch(:year),
382
- parts.fetch(:mon),
383
- parts.fetch(:mday),
407
+ year,
408
+ month,
409
+ day,
384
410
  parts.fetch(:hour, 0),
385
411
  parts.fetch(:min, 0),
386
412
  parts.fetch(:sec, 0) + parts.fetch(:sec_fraction, 0),
@@ -392,6 +418,9 @@ module ActiveSupport
392
418
  else
393
419
  TimeWithZone.new(nil, self, time)
394
420
  end
421
+
422
+ rescue Date::Error, KeyError
423
+ raise ArgumentError, "invalid date"
395
424
  end
396
425
 
397
426
  # Method for creating new ActiveSupport::TimeWithZone instance in time zone
@@ -495,10 +524,17 @@ module ActiveSupport
495
524
  end
496
525
 
497
526
  # 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.
527
+ # represented by +self+. Returns a local time with the appropriate offset
528
+ # -- if you want an ActiveSupport::TimeWithZone instance, use
529
+ # Time#in_time_zone() instead.
530
+ #
531
+ # As of tzinfo 2, utc_to_local returns a Time with a non-zero utc_offset.
532
+ # See the +utc_to_local_returns_utc_offset_times+ config for more info.
500
533
  def utc_to_local(time)
501
- tzinfo.utc_to_local(time)
534
+ tzinfo.utc_to_local(time).yield_self do |t|
535
+ ActiveSupport.utc_to_local_returns_utc_offset_times ?
536
+ t : Time.utc(t.year, t.month, t.day, t.hour, t.min, t.sec, t.sec_fraction * 1_000_000)
537
+ end
502
538
  end
503
539
 
504
540
  # Adjust the given time to the simultaneous time in UTC. Returns a
@@ -507,27 +543,27 @@ module ActiveSupport
507
543
  tzinfo.local_to_utc(time, dst)
508
544
  end
509
545
 
510
- # Available so that TimeZone instances respond like TZInfo::Timezone
546
+ # Available so that TimeZone instances respond like <tt>TZInfo::Timezone</tt>
511
547
  # instances.
512
548
  def period_for_utc(time)
513
549
  tzinfo.period_for_utc(time)
514
550
  end
515
551
 
516
- # Available so that TimeZone instances respond like TZInfo::Timezone
552
+ # Available so that TimeZone instances respond like <tt>TZInfo::Timezone</tt>
517
553
  # instances.
518
554
  def period_for_local(time, dst = true)
519
555
  tzinfo.period_for_local(time, dst) { |periods| periods.last }
520
556
  end
521
557
 
522
- def periods_for_local(time) #:nodoc:
558
+ def periods_for_local(time) # :nodoc:
523
559
  tzinfo.periods_for_local(time)
524
560
  end
525
561
 
526
- def init_with(coder) #:nodoc:
562
+ def init_with(coder) # :nodoc:
527
563
  initialize(coder["name"])
528
564
  end
529
565
 
530
- def encode_with(coder) #:nodoc:
566
+ def encode_with(coder) # :nodoc:
531
567
  coder.tag = "!ruby/object:#{self.class}"
532
568
  coder.map = { "name" => tzinfo.name }
533
569
  end
@@ -3,7 +3,7 @@
3
3
  require_relative "gem_version"
4
4
 
5
5
  module ActiveSupport
6
- # Returns the version of the currently loaded ActiveSupport as a <tt>Gem::Version</tt>
6
+ # Returns the currently loaded version of Active Support as a <tt>Gem::Version</tt>.
7
7
  def self.version
8
8
  gem_version
9
9
  end