activesupport 5.1.7 → 7.0.4.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 (279) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +259 -585
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -5
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +2 -0
  7. data/lib/active_support/array_inquirer.rb +4 -2
  8. data/lib/active_support/backtrace_cleaner.rb +33 -5
  9. data/lib/active_support/benchmarkable.rb +5 -3
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +50 -43
  12. data/lib/active_support/cache/mem_cache_store.rb +194 -67
  13. data/lib/active_support/cache/memory_store.rb +70 -34
  14. data/lib/active_support/cache/null_store.rb +18 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +474 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +73 -50
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +556 -220
  19. data/lib/active_support/callbacks.rb +264 -159
  20. data/lib/active_support/code_generator.rb +65 -0
  21. data/lib/active_support/concern.rb +81 -8
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
  23. data/lib/active_support/concurrency/share_lock.rb +4 -3
  24. data/lib/active_support/configurable.rb +17 -16
  25. data/lib/active_support/configuration_file.rb +51 -0
  26. data/lib/active_support/core_ext/array/access.rb +18 -8
  27. data/lib/active_support/core_ext/array/conversions.rb +20 -17
  28. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +8 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +4 -2
  33. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  34. data/lib/active_support/core_ext/array.rb +4 -1
  35. data/lib/active_support/core_ext/benchmark.rb +4 -2
  36. data/lib/active_support/core_ext/big_decimal/conversions.rb +3 -1
  37. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  38. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  39. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  40. data/lib/active_support/core_ext/class/subclasses.rb +10 -24
  41. data/lib/active_support/core_ext/class.rb +2 -0
  42. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  43. data/lib/active_support/core_ext/date/blank.rb +3 -1
  44. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  45. data/lib/active_support/core_ext/date/conversions.rb +24 -22
  46. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  47. data/lib/active_support/core_ext/date/zones.rb +2 -0
  48. data/lib/active_support/core_ext/date.rb +3 -0
  49. data/lib/active_support/core_ext/date_and_time/calculations.rb +65 -41
  50. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  51. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +3 -1
  54. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  56. data/lib/active_support/core_ext/date_time/conversions.rb +15 -14
  57. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  58. data/lib/active_support/core_ext/date_time.rb +3 -0
  59. data/lib/active_support/core_ext/digest/uuid.rb +42 -14
  60. data/lib/active_support/core_ext/digest.rb +3 -0
  61. data/lib/active_support/core_ext/enumerable.rb +244 -72
  62. data/lib/active_support/core_ext/file/atomic.rb +6 -2
  63. data/lib/active_support/core_ext/file.rb +2 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +7 -6
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +4 -2
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  69. data/lib/active_support/core_ext/hash/keys.rb +4 -31
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  71. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  72. data/lib/active_support/core_ext/hash.rb +3 -2
  73. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  74. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  75. data/lib/active_support/core_ext/integer/time.rb +7 -14
  76. data/lib/active_support/core_ext/integer.rb +2 -0
  77. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  78. data/lib/active_support/core_ext/kernel/reporting.rb +6 -4
  79. data/lib/active_support/core_ext/kernel/singleton_class.rb +3 -1
  80. data/lib/active_support/core_ext/kernel.rb +2 -1
  81. data/lib/active_support/core_ext/load_error.rb +3 -8
  82. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  83. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  84. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  85. data/lib/active_support/core_ext/module/attribute_accessors.rb +46 -56
  86. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +36 -27
  87. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  88. data/lib/active_support/core_ext/module/delegation.rb +97 -58
  89. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  90. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  91. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  92. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  93. data/lib/active_support/core_ext/module.rb +3 -1
  94. data/lib/active_support/core_ext/name_error.rb +30 -2
  95. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  96. data/lib/active_support/core_ext/numeric/conversions.rb +134 -129
  97. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  98. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  99. data/lib/active_support/core_ext/numeric.rb +3 -1
  100. data/lib/active_support/core_ext/object/acts_like.rb +41 -6
  101. data/lib/active_support/core_ext/object/blank.rb +15 -5
  102. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  103. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  104. data/lib/active_support/core_ext/object/duplicable.rb +16 -110
  105. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  106. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  107. data/lib/active_support/core_ext/object/json.rb +51 -26
  108. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  109. data/lib/active_support/core_ext/object/to_query.rb +4 -2
  110. data/lib/active_support/core_ext/object/try.rb +26 -14
  111. data/lib/active_support/core_ext/object/with_options.rb +24 -3
  112. data/lib/active_support/core_ext/object.rb +2 -0
  113. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  114. data/lib/active_support/core_ext/pathname.rb +3 -0
  115. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  116. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  117. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  118. data/lib/active_support/core_ext/range/each.rb +6 -3
  119. data/lib/active_support/core_ext/range/include_time_with_zone.rb +7 -0
  120. data/lib/active_support/core_ext/range/overlaps.rb +3 -1
  121. data/lib/active_support/core_ext/range.rb +4 -1
  122. data/lib/active_support/core_ext/regexp.rb +10 -5
  123. data/lib/active_support/core_ext/securerandom.rb +25 -3
  124. data/lib/active_support/core_ext/string/access.rb +7 -16
  125. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  126. data/lib/active_support/core_ext/string/conversions.rb +5 -2
  127. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  128. data/lib/active_support/core_ext/string/filters.rb +44 -1
  129. data/lib/active_support/core_ext/string/indent.rb +2 -0
  130. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  131. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  132. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  133. data/lib/active_support/core_ext/string/output_safety.rb +135 -27
  134. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  135. data/lib/active_support/core_ext/string/strip.rb +5 -1
  136. data/lib/active_support/core_ext/string/zones.rb +2 -0
  137. data/lib/active_support/core_ext/string.rb +2 -0
  138. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  139. data/lib/active_support/core_ext/symbol.rb +3 -0
  140. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  141. data/lib/active_support/core_ext/time/calculations.rb +81 -24
  142. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  143. data/lib/active_support/core_ext/time/conversions.rb +17 -12
  144. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  145. data/lib/active_support/core_ext/time/zones.rb +12 -25
  146. data/lib/active_support/core_ext/time.rb +3 -0
  147. data/lib/active_support/core_ext/uri.rb +4 -23
  148. data/lib/active_support/core_ext.rb +4 -1
  149. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  150. data/lib/active_support/current_attributes.rb +226 -0
  151. data/lib/active_support/dependencies/autoload.rb +2 -0
  152. data/lib/active_support/dependencies/interlock.rb +12 -18
  153. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  154. data/lib/active_support/dependencies.rb +59 -715
  155. data/lib/active_support/deprecation/behaviors.rb +48 -13
  156. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  157. data/lib/active_support/deprecation/disallowed.rb +56 -0
  158. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  159. data/lib/active_support/deprecation/method_wrappers.rb +29 -21
  160. data/lib/active_support/deprecation/proxy_wrappers.rb +34 -8
  161. data/lib/active_support/deprecation/reporting.rb +54 -9
  162. data/lib/active_support/deprecation.rb +10 -3
  163. data/lib/active_support/descendants_tracker.rb +192 -34
  164. data/lib/active_support/digest.rb +22 -0
  165. data/lib/active_support/duration/iso8601_parser.rb +9 -9
  166. data/lib/active_support/duration/iso8601_serializer.rb +29 -15
  167. data/lib/active_support/duration.rb +158 -72
  168. data/lib/active_support/encrypted_configuration.rb +56 -0
  169. data/lib/active_support/encrypted_file.rb +129 -0
  170. data/lib/active_support/environment_inquirer.rb +20 -0
  171. data/lib/active_support/error_reporter.rb +117 -0
  172. data/lib/active_support/evented_file_update_checker.rb +87 -122
  173. data/lib/active_support/execution_context/test_helper.rb +13 -0
  174. data/lib/active_support/execution_context.rb +53 -0
  175. data/lib/active_support/execution_wrapper.rb +46 -21
  176. data/lib/active_support/executor/test_helper.rb +7 -0
  177. data/lib/active_support/executor.rb +2 -0
  178. data/lib/active_support/file_update_checker.rb +2 -1
  179. data/lib/active_support/fork_tracker.rb +71 -0
  180. data/lib/active_support/gem_version.rb +7 -5
  181. data/lib/active_support/gzip.rb +2 -0
  182. data/lib/active_support/hash_with_indifferent_access.rb +126 -42
  183. data/lib/active_support/html_safe_translation.rb +43 -0
  184. data/lib/active_support/i18n.rb +5 -1
  185. data/lib/active_support/i18n_railtie.rb +19 -14
  186. data/lib/active_support/inflections.rb +2 -0
  187. data/lib/active_support/inflector/inflections.rb +41 -14
  188. data/lib/active_support/inflector/methods.rb +73 -87
  189. data/lib/active_support/inflector/transliterate.rb +56 -18
  190. data/lib/active_support/inflector.rb +2 -0
  191. data/lib/active_support/isolated_execution_state.rb +72 -0
  192. data/lib/active_support/json/decoding.rb +27 -26
  193. data/lib/active_support/json/encoding.rb +16 -6
  194. data/lib/active_support/json.rb +2 -0
  195. data/lib/active_support/key_generator.rb +25 -38
  196. data/lib/active_support/lazy_load_hooks.rb +35 -6
  197. data/lib/active_support/locale/en.rb +33 -0
  198. data/lib/active_support/locale/en.yml +8 -4
  199. data/lib/active_support/log_subscriber/test_helper.rb +4 -2
  200. data/lib/active_support/log_subscriber.rb +54 -13
  201. data/lib/active_support/logger.rb +4 -17
  202. data/lib/active_support/logger_silence.rb +13 -20
  203. data/lib/active_support/logger_thread_safe_level.rb +48 -10
  204. data/lib/active_support/message_encryptor.rb +111 -37
  205. data/lib/active_support/message_verifier.rb +124 -21
  206. data/lib/active_support/messages/metadata.rb +80 -0
  207. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  208. data/lib/active_support/messages/rotator.rb +57 -0
  209. data/lib/active_support/multibyte/chars.rb +19 -76
  210. data/lib/active_support/multibyte/unicode.rb +9 -331
  211. data/lib/active_support/multibyte.rb +3 -1
  212. data/lib/active_support/notifications/fanout.rb +165 -37
  213. data/lib/active_support/notifications/instrumenter.rb +92 -11
  214. data/lib/active_support/notifications.rb +96 -30
  215. data/lib/active_support/number_helper/number_converter.rb +8 -9
  216. data/lib/active_support/number_helper/number_to_currency_converter.rb +14 -12
  217. data/lib/active_support/number_helper/number_to_delimited_converter.rb +6 -3
  218. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -3
  219. data/lib/active_support/number_helper/number_to_human_size_converter.rb +7 -4
  220. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  221. data/lib/active_support/number_helper/number_to_phone_converter.rb +6 -3
  222. data/lib/active_support/number_helper/number_to_rounded_converter.rb +14 -27
  223. data/lib/active_support/number_helper/rounding_helper.rb +16 -34
  224. data/lib/active_support/number_helper.rb +38 -12
  225. data/lib/active_support/option_merger.rb +19 -6
  226. data/lib/active_support/ordered_hash.rb +4 -2
  227. data/lib/active_support/ordered_options.rb +18 -6
  228. data/lib/active_support/parameter_filter.rb +138 -0
  229. data/lib/active_support/per_thread_registry.rb +8 -1
  230. data/lib/active_support/proxy_object.rb +2 -0
  231. data/lib/active_support/rails.rb +3 -10
  232. data/lib/active_support/railtie.rb +112 -11
  233. data/lib/active_support/reloader.rb +12 -11
  234. data/lib/active_support/rescuable.rb +19 -18
  235. data/lib/active_support/ruby_features.rb +7 -0
  236. data/lib/active_support/secure_compare_rotator.rb +51 -0
  237. data/lib/active_support/security_utils.rb +26 -15
  238. data/lib/active_support/string_inquirer.rb +4 -3
  239. data/lib/active_support/subscriber.rb +81 -42
  240. data/lib/active_support/tagged_logging.rb +45 -9
  241. data/lib/active_support/test_case.rb +86 -2
  242. data/lib/active_support/testing/assertions.rb +89 -21
  243. data/lib/active_support/testing/autorun.rb +2 -0
  244. data/lib/active_support/testing/constant_lookup.rb +2 -0
  245. data/lib/active_support/testing/declarative.rb +2 -0
  246. data/lib/active_support/testing/deprecation.rb +54 -2
  247. data/lib/active_support/testing/file_fixtures.rb +4 -0
  248. data/lib/active_support/testing/isolation.rb +6 -4
  249. data/lib/active_support/testing/method_call_assertions.rb +34 -5
  250. data/lib/active_support/testing/parallelization/server.rb +82 -0
  251. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  252. data/lib/active_support/testing/parallelization.rb +55 -0
  253. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  254. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  255. data/lib/active_support/testing/stream.rb +6 -7
  256. data/lib/active_support/testing/tagged_logging.rb +3 -1
  257. data/lib/active_support/testing/time_helpers.rb +91 -15
  258. data/lib/active_support/time.rb +2 -0
  259. data/lib/active_support/time_with_zone.rb +168 -56
  260. data/lib/active_support/values/time_zone.rb +85 -37
  261. data/lib/active_support/version.rb +3 -1
  262. data/lib/active_support/xml_mini/jdom.rb +6 -5
  263. data/lib/active_support/xml_mini/libxml.rb +9 -7
  264. data/lib/active_support/xml_mini/libxmlsax.rb +7 -5
  265. data/lib/active_support/xml_mini/nokogiri.rb +8 -6
  266. data/lib/active_support/xml_mini/nokogirisax.rb +6 -4
  267. data/lib/active_support/xml_mini/rexml.rb +13 -4
  268. data/lib/active_support/xml_mini.rb +10 -15
  269. data/lib/active_support.rb +30 -9
  270. metadata +76 -35
  271. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  272. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  273. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  274. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  275. data/lib/active_support/core_ext/marshal.rb +0 -22
  276. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  277. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  278. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  279. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,9 +1,12 @@
1
- require "active_support/core_ext/string/strip" # for strip_heredoc
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/redefine_method"
2
4
  require "active_support/core_ext/time/calculations"
3
5
  require "concurrent/map"
4
6
 
5
7
  module ActiveSupport
6
8
  module Testing
9
+ # Manages stubs for TimeHelpers
7
10
  class SimpleStubs # :nodoc:
8
11
  Stub = Struct.new(:object, :method_name, :original_method)
9
12
 
@@ -11,6 +14,13 @@ module ActiveSupport
11
14
  @stubs = Concurrent::Map.new { |h, k| h[k] = {} }
12
15
  end
13
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
14
24
  def stub_object(object, method_name, &block)
15
25
  if stub = stubbing(object, method_name)
16
26
  unstub_object(stub)
@@ -20,10 +30,11 @@ module ActiveSupport
20
30
 
21
31
  @stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
22
32
 
23
- object.singleton_class.send :alias_method, new_name, method_name
33
+ object.singleton_class.alias_method new_name, method_name
24
34
  object.define_singleton_method(method_name, &block)
25
35
  end
26
36
 
37
+ # Remove all object-method stubs held by this instance
27
38
  def unstub_all!
28
39
  @stubs.each_value do |object_stubs|
29
40
  object_stubs.each_value do |stub|
@@ -33,24 +44,37 @@ module ActiveSupport
33
44
  @stubs.clear
34
45
  end
35
46
 
47
+ # Returns the Stub for object#method_name
48
+ # (nil if it is not stubbed)
36
49
  def stubbing(object, method_name)
37
50
  @stubs[object.object_id][method_name]
38
51
  end
39
52
 
40
- private
53
+ # Returns true if any stubs are set, false if there are none
54
+ def stubbed?
55
+ !@stubs.empty?
56
+ end
41
57
 
58
+ private
59
+ # Restores the original object.method described by the Stub
42
60
  def unstub_object(stub)
43
61
  singleton_class = stub.object.singleton_class
44
- singleton_class.send :undef_method, stub.method_name
45
- singleton_class.send :alias_method, stub.method_name, stub.original_method
46
- 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
47
65
  end
48
66
  end
49
67
 
50
68
  # Contains helpers that help you test passage of time.
51
69
  module TimeHelpers
70
+ def after_teardown
71
+ travel_back
72
+ super
73
+ end
74
+
52
75
  # Changes current time to the time in the future or in the past by a given time difference by
53
- # stubbing +Time.now+, +Date.today+, and +DateTime.now+.
76
+ # stubbing +Time.now+, +Date.today+, and +DateTime.now+. The stubs are automatically removed
77
+ # at the end of the test.
54
78
  #
55
79
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
56
80
  # travel 1.day
@@ -72,9 +96,10 @@ module ActiveSupport
72
96
 
73
97
  # Changes current time to the given time by stubbing +Time.now+,
74
98
  # +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
99
+ # The stubs are automatically removed at the end of the test.
75
100
  #
76
101
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
77
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
102
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
78
103
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
79
104
  # Date.current # => Wed, 24 Nov 2004
80
105
  # DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
@@ -96,13 +121,13 @@ module ActiveSupport
96
121
  # state at the end of the block:
97
122
  #
98
123
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
99
- # 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
100
125
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
101
126
  # end
102
127
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
103
128
  def travel_to(date_or_time)
104
- if block_given? && simple_stubs.stubbing(Time, :now)
105
- travel_to_nested_block_call = <<-MSG.strip_heredoc
129
+ if block_given? && in_block
130
+ travel_to_nested_block_call = <<~MSG
106
131
 
107
132
  Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
108
133
 
@@ -131,40 +156,91 @@ module ActiveSupport
131
156
 
132
157
  if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
133
158
  now = date_or_time.midnight.to_time
159
+ elsif date_or_time.is_a?(String)
160
+ now = Time.zone.parse(date_or_time)
134
161
  else
135
162
  now = date_or_time.to_time.change(usec: 0)
136
163
  end
137
164
 
165
+ stubbed_time = Time.now if simple_stubs.stubbing(Time, :now)
138
166
  simple_stubs.stub_object(Time, :now) { at(now.to_i) }
139
167
  simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
140
168
  simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
141
169
 
142
170
  if block_given?
143
171
  begin
172
+ self.in_block = true
144
173
  yield
145
174
  ensure
146
- travel_back
175
+ if stubbed_time
176
+ travel_to stubbed_time
177
+ else
178
+ travel_back
179
+ end
180
+ self.in_block = false
147
181
  end
148
182
  end
149
183
  end
150
184
 
151
185
  # Returns the current time back to its original state, by removing the stubs added by
152
- # `travel` and `travel_to`.
186
+ # +travel+, +travel_to+, and +freeze_time+.
153
187
  #
154
188
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
155
- # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
189
+ #
190
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
156
191
  # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
192
+ #
157
193
  # travel_back
158
194
  # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
195
+ #
196
+ # This method also accepts a block, which brings the stubs back at the end of the block:
197
+ #
198
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
199
+ #
200
+ # travel_to Time.zone.local(2004, 11, 24, 1, 4, 44)
201
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
202
+ #
203
+ # travel_back do
204
+ # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
205
+ # end
206
+ #
207
+ # Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
159
208
  def travel_back
209
+ stubbed_time = Time.current if block_given? && simple_stubs.stubbed?
210
+
160
211
  simple_stubs.unstub_all!
212
+ yield if block_given?
213
+ ensure
214
+ travel_to stubbed_time if stubbed_time
161
215
  end
216
+ alias_method :unfreeze_time, :travel_back
162
217
 
163
- private
218
+ # Calls +travel_to+ with +Time.now+.
219
+ #
220
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
221
+ # freeze_time
222
+ # sleep(1)
223
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
224
+ #
225
+ # This method also accepts a block, which will return the current time back to its original
226
+ # state at the end of the block:
227
+ #
228
+ # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00
229
+ # freeze_time do
230
+ # sleep(1)
231
+ # User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00
232
+ # end
233
+ # Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00
234
+ def freeze_time(&block)
235
+ travel_to Time.now, &block
236
+ end
164
237
 
238
+ private
165
239
  def simple_stubs
166
240
  @simple_stubs ||= SimpleStubs.new
167
241
  end
242
+
243
+ attr_accessor :in_block
168
244
  end
169
245
  end
170
246
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  autoload :Duration, "active_support/duration"
3
5
  autoload :TimeWithZone, "active_support/time_with_zone"
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "yaml"
4
+
1
5
  require "active_support/duration"
2
6
  require "active_support/values/time_zone"
3
7
  require "active_support/core_ext/object/acts_like"
@@ -9,40 +13,47 @@ module ActiveSupport
9
13
  # system's <tt>ENV['TZ']</tt> zone.
10
14
  #
11
15
  # You shouldn't ever need to create a TimeWithZone instance directly via +new+.
12
- # Instead use methods +local+, +parse+, +at+ and +now+ on TimeZone instances,
16
+ # Instead use methods +local+, +parse+, +at+, and +now+ on TimeZone instances,
13
17
  # and +in_time_zone+ on Time and DateTime instances.
14
18
  #
15
19
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
16
- # Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
17
- # Time.zone.parse('2007-02-10 15:30:45') # => Sat, 10 Feb 2007 15:30:45 EST -05:00
18
- # Time.zone.at(1171139445) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
19
- # Time.zone.now # => Sun, 18 May 2008 13:07:55 EDT -04:00
20
- # 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
21
25
  #
22
26
  # See Time and TimeZone for further documentation of these methods.
23
27
  #
24
28
  # TimeWithZone instances implement the same API as Ruby Time instances, so
25
29
  # that Time and TimeWithZone instances are interchangeable.
26
30
  #
27
- # 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
28
32
  # t.hour # => 13
29
33
  # t.dst? # => true
30
34
  # t.utc_offset # => -14400
31
35
  # t.zone # => "EDT"
32
- # t.to_s(:rfc822) # => "Sun, 18 May 2008 13:27:25 -0400"
33
- # t + 1.day # => Mon, 19 May 2008 13:27:25 EDT -04:00
34
- # 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
35
39
  # t > Time.utc(1999) # => true
36
40
  # t.is_a?(Time) # => true
37
41
  # t.is_a?(ActiveSupport::TimeWithZone) # => true
38
42
  class TimeWithZone
39
43
  # Report class name as 'Time' to thwart type checking.
40
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
+
41
52
  "Time"
42
53
  end
43
54
 
44
- PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N".freeze }
45
- PRECISIONS[0] = "%FT%T".freeze
55
+ PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N" }
56
+ PRECISIONS[0] = "%FT%T"
46
57
 
47
58
  include Comparable, DateAndTime::Compatibility
48
59
  attr_reader :time_zone
@@ -55,19 +66,19 @@ module ActiveSupport
55
66
 
56
67
  # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
57
68
  def time
58
- @time ||= period.to_local(@utc)
69
+ @time ||= incorporate_utc_offset(@utc, utc_offset)
59
70
  end
60
71
 
61
72
  # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
62
73
  def utc
63
- @utc ||= period.to_utc(@time)
74
+ @utc ||= incorporate_utc_offset(@time, -utc_offset)
64
75
  end
65
76
  alias_method :comparable_time, :utc
66
77
  alias_method :getgm, :utc
67
78
  alias_method :getutc, :utc
68
79
  alias_method :gmtime, :utc
69
80
 
70
- # Returns the underlying TZInfo::TimezonePeriod.
81
+ # Returns the underlying <tt>TZInfo::TimezonePeriod</tt>.
71
82
  def period
72
83
  @period ||= time_zone.period_for_utc(@utc)
73
84
  end
@@ -102,13 +113,13 @@ module ActiveSupport
102
113
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
103
114
  # Time.zone.now.utc? # => false
104
115
  def utc?
105
- period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
116
+ zone == "UTC" || zone == "UCT"
106
117
  end
107
118
  alias_method :gmt?, :utc?
108
119
 
109
120
  # Returns the offset from current time to UTC time in seconds.
110
121
  def utc_offset
111
- period.utc_total_offset
122
+ period.observed_utc_offset
112
123
  end
113
124
  alias_method :gmt_offset, :utc_offset
114
125
  alias_method :gmtoff, :utc_offset
@@ -130,14 +141,14 @@ module ActiveSupport
130
141
  # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
131
142
  # Time.zone.now.zone # => "EST"
132
143
  def zone
133
- period.zone_identifier.to_s
144
+ period.abbreviation
134
145
  end
135
146
 
136
147
  # Returns a string of the object's date, time, zone, and offset from UTC.
137
148
  #
138
- # 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"
139
150
  def inspect
140
- "#{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}"
141
152
  end
142
153
 
143
154
  # Returns a string of the object's date and time in the ISO 8601 standard
@@ -145,7 +156,7 @@ module ActiveSupport
145
156
  #
146
157
  # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
147
158
  def xmlschema(fraction_digits = 0)
148
- "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z'.freeze)}"
159
+ "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z')}"
149
160
  end
150
161
  alias_method :iso8601, :xmlschema
151
162
  alias_method :rfc3339, :xmlschema
@@ -170,12 +181,11 @@ module ActiveSupport
170
181
  end
171
182
  end
172
183
 
173
- def init_with(coder) #:nodoc:
184
+ def init_with(coder) # :nodoc:
174
185
  initialize(coder["utc"], coder["zone"], coder["time"])
175
186
  end
176
187
 
177
- def encode_with(coder) #:nodoc:
178
- coder.tag = "!ruby/object:ActiveSupport::TimeWithZone"
188
+ def encode_with(coder) # :nodoc:
179
189
  coder.map = { "utc" => utc, "zone" => time_zone, "time" => time }
180
190
  end
181
191
 
@@ -192,25 +202,53 @@ module ActiveSupport
192
202
  #
193
203
  # Time.zone.now.rfc2822 # => "Tue, 01 Jan 2013 04:51:39 +0000"
194
204
  def rfc2822
195
- to_s(:rfc822)
205
+ to_fs(:rfc822)
196
206
  end
197
207
  alias_method :rfc822, :rfc2822
198
208
 
209
+ NOT_SET = Object.new # :nodoc:
210
+
199
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
+
233
+ # Returns a string of the object's date and time.
234
+ #
235
+ # This method is aliased to <tt>to_formatted_s</tt>.
236
+ #
200
237
  # Accepts an optional <tt>format</tt>:
201
238
  # * <tt>:default</tt> - default value, mimics Ruby Time#to_s format.
202
- # * <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).
203
240
  # * Any key in <tt>Time::DATE_FORMATS</tt> can be used. See active_support/core_ext/time/conversions.rb.
204
- def to_s(format = :default)
241
+ def to_fs(format = :default)
205
242
  if format == :db
206
- utc.to_s(format)
243
+ utc.to_fs(format)
207
244
  elsif formatter = ::Time::DATE_FORMATS[format]
208
245
  formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
209
246
  else
210
- "#{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')}"
211
249
  end
212
250
  end
213
- alias_method :to_formatted_s, :to_s
251
+ alias_method :to_formatted_s, :to_fs
214
252
 
215
253
  # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
216
254
  # so that zone information is correct.
@@ -223,6 +261,8 @@ module ActiveSupport
223
261
  def <=>(other)
224
262
  utc <=> other
225
263
  end
264
+ alias_method :before?, :<
265
+ alias_method :after?, :>
226
266
 
227
267
  # Returns true if the current object's time is within the specified
228
268
  # +min+ and +max+ time.
@@ -241,6 +281,20 @@ module ActiveSupport
241
281
  time.today?
242
282
  end
243
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
+
244
298
  # Returns true if the current object's time is in the future.
245
299
  def future?
246
300
  utc.future?
@@ -259,8 +313,8 @@ module ActiveSupport
259
313
  # value as a new TimeWithZone object.
260
314
  #
261
315
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
262
- # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
263
- # 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
264
318
  #
265
319
  # If we're adding a Duration of variable length (i.e., years, months, days),
266
320
  # move forward from #time, otherwise move forward from #utc, for accuracy
@@ -269,8 +323,8 @@ module ActiveSupport
269
323
  # For instance, a time + 24.hours will advance exactly 24 hours, while a
270
324
  # time + 1.day will advance 23-25 hours, depending on the day.
271
325
  #
272
- # now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
273
- # 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
274
328
  def +(other)
275
329
  if duration_of_variable_length?(other)
276
330
  method_missing(:+, other)
@@ -282,12 +336,13 @@ module ActiveSupport
282
336
  alias_method :since, :+
283
337
  alias_method :in, :+
284
338
 
285
- # Returns a new TimeWithZone object that represents the difference between
286
- # 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. In which case, it will subtract the
341
+ # other time and return the difference in seconds as a Float.
287
342
  #
288
343
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
289
- # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
290
- # now - 1000 # => Mon, 03 Nov 2014 00:09:48 EST -05:00
344
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
345
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
291
346
  #
292
347
  # If subtracting a Duration of variable length (i.e., years, months, days),
293
348
  # move backward from #time, otherwise move backward from #utc, for accuracy
@@ -296,8 +351,14 @@ module ActiveSupport
296
351
  # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
297
352
  # time - 1.day will subtract 23-25 hours, depending on the day.
298
353
  #
299
- # now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
300
- # now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
354
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
355
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
356
+ #
357
+ # If both the TimeWithZone object and the other value act like Time, a Float
358
+ # will be returned.
359
+ #
360
+ # Time.zone.now - 1.day.ago # => 86399.999967
361
+ #
301
362
  def -(other)
302
363
  if other.acts_like?(:time)
303
364
  to_time - other.to_time
@@ -313,8 +374,8 @@ module ActiveSupport
313
374
  # the result as a new TimeWithZone object.
314
375
  #
315
376
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
316
- # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
317
- # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48 EST -05:00
377
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28.725182881 EST -05:00
378
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48.725182881 EST -05:00
318
379
  #
319
380
  # If we're subtracting a Duration of variable length (i.e., years, months,
320
381
  # days), move backward from #time, otherwise move backward from #utc, for
@@ -324,12 +385,48 @@ module ActiveSupport
324
385
  # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
325
386
  # the day.
326
387
  #
327
- # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
328
- # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
388
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28.725182881 EDT -04:00
389
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28.725182881 EDT -04:00
329
390
  def ago(other)
330
391
  since(-other)
331
392
  end
332
393
 
394
+ # Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
395
+ # been changed according to the +options+ parameter. The time options (<tt>:hour</tt>,
396
+ # <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly,
397
+ # so if only the hour is passed, then minute, sec, usec, and nsec is set to 0. If the
398
+ # hour and minute is passed, then sec, usec, and nsec is set to 0. The +options+
399
+ # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
400
+ # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>,
401
+ # <tt>:nsec</tt>, <tt>:offset</tt>, <tt>:zone</tt>. Pass either <tt>:usec</tt>
402
+ # or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
403
+ # <tt>:offset</tt>, not both.
404
+ #
405
+ # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15.116992711 EST -05:00
406
+ # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15.116992711 EST -05:00
407
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00.116992711 EST -05:00
408
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00.116992711 EST -05:00
409
+ # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
410
+ # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15.116992711 HST -10:00
411
+ def change(options)
412
+ if options[:zone] && options[:offset]
413
+ raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
414
+ end
415
+
416
+ new_time = time.change(options)
417
+
418
+ if options[:zone]
419
+ new_zone = ::Time.find_zone(options[:zone])
420
+ elsif options[:offset]
421
+ new_zone = ::Time.find_zone(new_time.utc_offset)
422
+ end
423
+
424
+ new_zone ||= time_zone
425
+ periods = new_zone.periods_for_local(new_time)
426
+
427
+ self.class.new(nil, new_zone, new_time, periods.include?(period) ? period : nil)
428
+ end
429
+
333
430
  # Uses Date to provide precise Time calculations for years, months, and days
334
431
  # according to the proleptic Gregorian calendar. The result is returned as a
335
432
  # new TimeWithZone object.
@@ -343,14 +440,14 @@ module ActiveSupport
343
440
  # accuracy when moving across DST boundaries.
344
441
  #
345
442
  # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
346
- # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
347
- # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29 EDT -04:00
348
- # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28 EDT -04:00
349
- # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28 EST -05:00
350
- # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28 EST -05:00
351
- # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28 EST -05:00
352
- # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28 EST -05:00
353
- # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28 EST -05:00
443
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28.558049687 EDT -04:00
444
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29.558049687 EDT -04:00
445
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28.558049687 EDT -04:00
446
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28.558049687 EST -05:00
447
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28.558049687 EST -05:00
448
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28.558049687 EST -05:00
449
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28.558049687 EST -05:00
450
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28.558049687 EST -05:00
354
451
  def advance(options)
355
452
  # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
356
453
  # otherwise advance from #utc, for accuracy when moving across DST boundaries
@@ -372,13 +469,13 @@ module ActiveSupport
372
469
  # Returns Array of parts of Time in sequence of
373
470
  # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
374
471
  #
375
- # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
472
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27.485278555 UTC +00:00
376
473
  # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
377
474
  def to_a
378
475
  [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
379
476
  end
380
477
 
381
- # Returns the object's date and time as a floating point number of seconds
478
+ # Returns the object's date and time as a floating-point number of seconds
382
479
  # since the Epoch (January 1, 1970 00:00 UTC).
383
480
  #
384
481
  # Time.zone.now.to_f # => 1417709320.285418
@@ -472,10 +569,20 @@ module ActiveSupport
472
569
  def method_missing(sym, *args, &block)
473
570
  wrap_with_time_zone time.__send__(sym, *args, &block)
474
571
  rescue NoMethodError => e
475
- raise e, e.message.sub(time.inspect, inspect), e.backtrace
572
+ raise e, e.message.sub(time.inspect, inspect).sub("Time", "ActiveSupport::TimeWithZone"), e.backtrace
476
573
  end
477
574
 
478
575
  private
576
+ SECONDS_PER_DAY = 86400
577
+
578
+ def incorporate_utc_offset(time, offset)
579
+ if time.kind_of?(Date)
580
+ time + Rational(offset, SECONDS_PER_DAY)
581
+ else
582
+ time + offset
583
+ end
584
+ end
585
+
479
586
  def get_period_and_ensure_valid_local_time(period)
480
587
  # we don't want a Time.local instance enforcing its own DST rules as well,
481
588
  # so transfer time values to a utc constructor if necessary
@@ -496,7 +603,7 @@ module ActiveSupport
496
603
  end
497
604
 
498
605
  def duration_of_variable_length?(obj)
499
- ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) }
606
+ ActiveSupport::Duration === obj && obj.variable?
500
607
  end
501
608
 
502
609
  def wrap_with_time_zone(time)
@@ -511,3 +618,8 @@ module ActiveSupport
511
618
  end
512
619
  end
513
620
  end
621
+
622
+ # These prevent Psych from calling `ActiveSupport::TimeWithZone.name`
623
+ # and triggering the deprecation warning about the change in Rails 7.1.
624
+ YAML.load_tags["!ruby/object:ActiveSupport::TimeWithZone"] = "ActiveSupport::TimeWithZone"
625
+ YAML.dump_tags[ActiveSupport::TimeWithZone] = "!ruby/object:ActiveSupport::TimeWithZone"