activesupport 6.0.0

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 (250) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +572 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support.rb +96 -0
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/all.rb +5 -0
  8. data/lib/active_support/array_inquirer.rb +48 -0
  9. data/lib/active_support/backtrace_cleaner.rb +132 -0
  10. data/lib/active_support/benchmarkable.rb +51 -0
  11. data/lib/active_support/builder.rb +8 -0
  12. data/lib/active_support/cache.rb +830 -0
  13. data/lib/active_support/cache/file_store.rb +196 -0
  14. data/lib/active_support/cache/mem_cache_store.rb +212 -0
  15. data/lib/active_support/cache/memory_store.rb +174 -0
  16. data/lib/active_support/cache/null_store.rb +48 -0
  17. data/lib/active_support/cache/redis_cache_store.rb +488 -0
  18. data/lib/active_support/cache/strategy/local_cache.rb +194 -0
  19. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  20. data/lib/active_support/callbacks.rb +856 -0
  21. data/lib/active_support/concern.rb +171 -0
  22. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  23. data/lib/active_support/concurrency/share_lock.rb +227 -0
  24. data/lib/active_support/configurable.rb +146 -0
  25. data/lib/active_support/core_ext.rb +5 -0
  26. data/lib/active_support/core_ext/array.rb +9 -0
  27. data/lib/active_support/core_ext/array/access.rb +104 -0
  28. data/lib/active_support/core_ext/array/conversions.rb +213 -0
  29. data/lib/active_support/core_ext/array/extract.rb +21 -0
  30. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  31. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  32. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  33. data/lib/active_support/core_ext/array/prepend_and_append.rb +5 -0
  34. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  35. data/lib/active_support/core_ext/benchmark.rb +16 -0
  36. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  37. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  38. data/lib/active_support/core_ext/class.rb +4 -0
  39. data/lib/active_support/core_ext/class/attribute.rb +141 -0
  40. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  41. data/lib/active_support/core_ext/class/subclasses.rb +54 -0
  42. data/lib/active_support/core_ext/date.rb +7 -0
  43. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  44. data/lib/active_support/core_ext/date/blank.rb +14 -0
  45. data/lib/active_support/core_ext/date/calculations.rb +146 -0
  46. data/lib/active_support/core_ext/date/conversions.rb +96 -0
  47. data/lib/active_support/core_ext/date/zones.rb +8 -0
  48. data/lib/active_support/core_ext/date_and_time/calculations.rb +351 -0
  49. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  50. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  51. data/lib/active_support/core_ext/date_time.rb +7 -0
  52. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  54. data/lib/active_support/core_ext/date_time/calculations.rb +211 -0
  55. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  56. data/lib/active_support/core_ext/date_time/conversions.rb +107 -0
  57. data/lib/active_support/core_ext/digest.rb +3 -0
  58. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  59. data/lib/active_support/core_ext/enumerable.rb +188 -0
  60. data/lib/active_support/core_ext/file.rb +3 -0
  61. data/lib/active_support/core_ext/file/atomic.rb +70 -0
  62. data/lib/active_support/core_ext/hash.rb +10 -0
  63. data/lib/active_support/core_ext/hash/compact.rb +5 -0
  64. data/lib/active_support/core_ext/hash/conversions.rb +263 -0
  65. data/lib/active_support/core_ext/hash/deep_merge.rb +34 -0
  66. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  67. data/lib/active_support/core_ext/hash/except.rb +24 -0
  68. data/lib/active_support/core_ext/hash/indifferent_access.rb +24 -0
  69. data/lib/active_support/core_ext/hash/keys.rb +143 -0
  70. data/lib/active_support/core_ext/hash/reverse_merge.rb +25 -0
  71. data/lib/active_support/core_ext/hash/slice.rb +26 -0
  72. data/lib/active_support/core_ext/hash/transform_values.rb +5 -0
  73. data/lib/active_support/core_ext/integer.rb +5 -0
  74. data/lib/active_support/core_ext/integer/inflections.rb +31 -0
  75. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  76. data/lib/active_support/core_ext/integer/time.rb +22 -0
  77. data/lib/active_support/core_ext/kernel.rb +5 -0
  78. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  79. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  80. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  81. data/lib/active_support/core_ext/load_error.rb +9 -0
  82. data/lib/active_support/core_ext/marshal.rb +24 -0
  83. data/lib/active_support/core_ext/module.rb +13 -0
  84. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  85. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  86. data/lib/active_support/core_ext/module/attr_internal.rb +38 -0
  87. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  88. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +144 -0
  89. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  90. data/lib/active_support/core_ext/module/delegation.rb +313 -0
  91. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  92. data/lib/active_support/core_ext/module/introspection.rb +86 -0
  93. data/lib/active_support/core_ext/module/reachable.rb +6 -0
  94. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  95. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  96. data/lib/active_support/core_ext/name_error.rb +38 -0
  97. data/lib/active_support/core_ext/numeric.rb +5 -0
  98. data/lib/active_support/core_ext/numeric/bytes.rb +66 -0
  99. data/lib/active_support/core_ext/numeric/conversions.rb +136 -0
  100. data/lib/active_support/core_ext/numeric/inquiry.rb +5 -0
  101. data/lib/active_support/core_ext/numeric/time.rb +66 -0
  102. data/lib/active_support/core_ext/object.rb +16 -0
  103. data/lib/active_support/core_ext/object/acts_like.rb +21 -0
  104. data/lib/active_support/core_ext/object/blank.rb +155 -0
  105. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  106. data/lib/active_support/core_ext/object/deep_dup.rb +55 -0
  107. data/lib/active_support/core_ext/object/duplicable.rb +49 -0
  108. data/lib/active_support/core_ext/object/inclusion.rb +29 -0
  109. data/lib/active_support/core_ext/object/instance_variables.rb +30 -0
  110. data/lib/active_support/core_ext/object/json.rb +228 -0
  111. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  112. data/lib/active_support/core_ext/object/to_query.rb +89 -0
  113. data/lib/active_support/core_ext/object/try.rb +156 -0
  114. data/lib/active_support/core_ext/object/with_options.rb +82 -0
  115. data/lib/active_support/core_ext/range.rb +7 -0
  116. data/lib/active_support/core_ext/range/compare_range.rb +70 -0
  117. data/lib/active_support/core_ext/range/conversions.rb +41 -0
  118. data/lib/active_support/core_ext/range/each.rb +25 -0
  119. data/lib/active_support/core_ext/range/include_range.rb +9 -0
  120. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  121. data/lib/active_support/core_ext/range/overlaps.rb +10 -0
  122. data/lib/active_support/core_ext/regexp.rb +7 -0
  123. data/lib/active_support/core_ext/securerandom.rb +45 -0
  124. data/lib/active_support/core_ext/string.rb +15 -0
  125. data/lib/active_support/core_ext/string/access.rb +114 -0
  126. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  127. data/lib/active_support/core_ext/string/conversions.rb +59 -0
  128. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  129. data/lib/active_support/core_ext/string/filters.rb +145 -0
  130. data/lib/active_support/core_ext/string/indent.rb +45 -0
  131. data/lib/active_support/core_ext/string/inflections.rb +259 -0
  132. data/lib/active_support/core_ext/string/inquiry.rb +15 -0
  133. data/lib/active_support/core_ext/string/multibyte.rb +58 -0
  134. data/lib/active_support/core_ext/string/output_safety.rb +314 -0
  135. data/lib/active_support/core_ext/string/starts_ends_with.rb +6 -0
  136. data/lib/active_support/core_ext/string/strip.rb +27 -0
  137. data/lib/active_support/core_ext/string/zones.rb +16 -0
  138. data/lib/active_support/core_ext/time.rb +7 -0
  139. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  140. data/lib/active_support/core_ext/time/calculations.rb +344 -0
  141. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  142. data/lib/active_support/core_ext/time/conversions.rb +72 -0
  143. data/lib/active_support/core_ext/time/zones.rb +113 -0
  144. data/lib/active_support/core_ext/uri.rb +25 -0
  145. data/lib/active_support/current_attributes.rb +203 -0
  146. data/lib/active_support/dependencies.rb +806 -0
  147. data/lib/active_support/dependencies/autoload.rb +79 -0
  148. data/lib/active_support/dependencies/interlock.rb +57 -0
  149. data/lib/active_support/dependencies/zeitwerk_integration.rb +110 -0
  150. data/lib/active_support/deprecation.rb +46 -0
  151. data/lib/active_support/deprecation/behaviors.rb +109 -0
  152. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  153. data/lib/active_support/deprecation/instance_delegator.rb +39 -0
  154. data/lib/active_support/deprecation/method_wrappers.rb +78 -0
  155. data/lib/active_support/deprecation/proxy_wrappers.rb +173 -0
  156. data/lib/active_support/deprecation/reporting.rb +114 -0
  157. data/lib/active_support/descendants_tracker.rb +109 -0
  158. data/lib/active_support/digest.rb +20 -0
  159. data/lib/active_support/duration.rb +433 -0
  160. data/lib/active_support/duration/iso8601_parser.rb +124 -0
  161. data/lib/active_support/duration/iso8601_serializer.rb +54 -0
  162. data/lib/active_support/encrypted_configuration.rb +45 -0
  163. data/lib/active_support/encrypted_file.rb +100 -0
  164. data/lib/active_support/evented_file_update_checker.rb +235 -0
  165. data/lib/active_support/execution_wrapper.rb +129 -0
  166. data/lib/active_support/executor.rb +8 -0
  167. data/lib/active_support/file_update_checker.rb +163 -0
  168. data/lib/active_support/gem_version.rb +17 -0
  169. data/lib/active_support/gzip.rb +38 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +399 -0
  171. data/lib/active_support/i18n.rb +16 -0
  172. data/lib/active_support/i18n_railtie.rb +126 -0
  173. data/lib/active_support/inflections.rb +72 -0
  174. data/lib/active_support/inflector.rb +9 -0
  175. data/lib/active_support/inflector/inflections.rb +257 -0
  176. data/lib/active_support/inflector/methods.rb +398 -0
  177. data/lib/active_support/inflector/transliterate.rb +147 -0
  178. data/lib/active_support/json.rb +4 -0
  179. data/lib/active_support/json/decoding.rb +76 -0
  180. data/lib/active_support/json/encoding.rb +134 -0
  181. data/lib/active_support/key_generator.rb +41 -0
  182. data/lib/active_support/lazy_load_hooks.rb +82 -0
  183. data/lib/active_support/locale/en.rb +31 -0
  184. data/lib/active_support/locale/en.yml +135 -0
  185. data/lib/active_support/log_subscriber.rb +135 -0
  186. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  187. data/lib/active_support/logger.rb +93 -0
  188. data/lib/active_support/logger_silence.rb +45 -0
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -0
  190. data/lib/active_support/message_encryptor.rb +227 -0
  191. data/lib/active_support/message_verifier.rb +205 -0
  192. data/lib/active_support/messages/metadata.rb +71 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  194. data/lib/active_support/messages/rotator.rb +56 -0
  195. data/lib/active_support/multibyte.rb +23 -0
  196. data/lib/active_support/multibyte/chars.rb +216 -0
  197. data/lib/active_support/multibyte/unicode.rb +157 -0
  198. data/lib/active_support/notifications.rb +253 -0
  199. data/lib/active_support/notifications/fanout.rb +244 -0
  200. data/lib/active_support/notifications/instrumenter.rb +164 -0
  201. data/lib/active_support/number_helper.rb +378 -0
  202. data/lib/active_support/number_helper/number_converter.rb +184 -0
  203. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  204. data/lib/active_support/number_helper/number_to_delimited_converter.rb +31 -0
  205. data/lib/active_support/number_helper/number_to_human_converter.rb +70 -0
  206. data/lib/active_support/number_helper/number_to_human_size_converter.rb +61 -0
  207. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  208. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  209. data/lib/active_support/number_helper/number_to_rounded_converter.rb +56 -0
  210. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  211. data/lib/active_support/option_merger.rb +27 -0
  212. data/lib/active_support/ordered_hash.rb +50 -0
  213. data/lib/active_support/ordered_options.rb +85 -0
  214. data/lib/active_support/parameter_filter.rb +129 -0
  215. data/lib/active_support/per_thread_registry.rb +60 -0
  216. data/lib/active_support/proxy_object.rb +15 -0
  217. data/lib/active_support/rails.rb +29 -0
  218. data/lib/active_support/railtie.rb +80 -0
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +174 -0
  221. data/lib/active_support/security_utils.rb +31 -0
  222. data/lib/active_support/string_inquirer.rb +34 -0
  223. data/lib/active_support/subscriber.rb +169 -0
  224. data/lib/active_support/tagged_logging.rb +88 -0
  225. data/lib/active_support/test_case.rb +163 -0
  226. data/lib/active_support/testing/assertions.rb +228 -0
  227. data/lib/active_support/testing/autorun.rb +7 -0
  228. data/lib/active_support/testing/constant_lookup.rb +51 -0
  229. data/lib/active_support/testing/declarative.rb +28 -0
  230. data/lib/active_support/testing/deprecation.rb +38 -0
  231. data/lib/active_support/testing/file_fixtures.rb +38 -0
  232. data/lib/active_support/testing/isolation.rb +110 -0
  233. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  234. data/lib/active_support/testing/parallelization.rb +128 -0
  235. data/lib/active_support/testing/setup_and_teardown.rb +55 -0
  236. data/lib/active_support/testing/stream.rb +44 -0
  237. data/lib/active_support/testing/tagged_logging.rb +27 -0
  238. data/lib/active_support/testing/time_helpers.rb +200 -0
  239. data/lib/active_support/time.rb +20 -0
  240. data/lib/active_support/time_with_zone.rb +561 -0
  241. data/lib/active_support/values/time_zone.rb +570 -0
  242. data/lib/active_support/version.rb +10 -0
  243. data/lib/active_support/xml_mini.rb +202 -0
  244. data/lib/active_support/xml_mini/jdom.rb +183 -0
  245. data/lib/active_support/xml_mini/libxml.rb +80 -0
  246. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  247. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  248. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  249. data/lib/active_support/xml_mini/rexml.rb +130 -0
  250. metadata +385 -0
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ autoload :Duration, "active_support/duration"
5
+ autoload :TimeWithZone, "active_support/time_with_zone"
6
+ autoload :TimeZone, "active_support/values/time_zone"
7
+ end
8
+
9
+ require "date"
10
+ require "time"
11
+
12
+ require "active_support/core_ext/time"
13
+ require "active_support/core_ext/date"
14
+ require "active_support/core_ext/date_time"
15
+
16
+ require "active_support/core_ext/integer/time"
17
+ require "active_support/core_ext/numeric/time"
18
+
19
+ require "active_support/core_ext/string/conversions"
20
+ require "active_support/core_ext/string/zones"
@@ -0,0 +1,561 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/duration"
4
+ require "active_support/values/time_zone"
5
+ require "active_support/core_ext/object/acts_like"
6
+ require "active_support/core_ext/date_and_time/compatibility"
7
+
8
+ module ActiveSupport
9
+ # A Time-like class that can represent a time in any time zone. Necessary
10
+ # because standard Ruby Time instances are limited to UTC and the
11
+ # system's <tt>ENV['TZ']</tt> zone.
12
+ #
13
+ # 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,
15
+ # and +in_time_zone+ on Time and DateTime instances.
16
+ #
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
23
+ #
24
+ # See Time and TimeZone for further documentation of these methods.
25
+ #
26
+ # TimeWithZone instances implement the same API as Ruby Time instances, so
27
+ # that Time and TimeWithZone instances are interchangeable.
28
+ #
29
+ # t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
30
+ # t.hour # => 13
31
+ # t.dst? # => true
32
+ # t.utc_offset # => -14400
33
+ # 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
37
+ # t > Time.utc(1999) # => true
38
+ # t.is_a?(Time) # => true
39
+ # t.is_a?(ActiveSupport::TimeWithZone) # => true
40
+ class TimeWithZone
41
+ # Report class name as 'Time' to thwart type checking.
42
+ def self.name
43
+ "Time"
44
+ end
45
+
46
+ PRECISIONS = Hash.new { |h, n| h[n] = "%FT%T.%#{n}N" }
47
+ PRECISIONS[0] = "%FT%T"
48
+
49
+ include Comparable, DateAndTime::Compatibility
50
+ attr_reader :time_zone
51
+
52
+ def initialize(utc_time, time_zone, local_time = nil, period = nil)
53
+ @utc = utc_time ? transfer_time_values_to_utc_constructor(utc_time) : nil
54
+ @time_zone, @time = time_zone, local_time
55
+ @period = @utc ? period : get_period_and_ensure_valid_local_time(period)
56
+ end
57
+
58
+ # Returns a <tt>Time</tt> instance that represents the time in +time_zone+.
59
+ def time
60
+ @time ||= period.to_local(@utc)
61
+ end
62
+
63
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
64
+ def utc
65
+ @utc ||= period.to_utc(@time)
66
+ end
67
+ alias_method :comparable_time, :utc
68
+ alias_method :getgm, :utc
69
+ alias_method :getutc, :utc
70
+ alias_method :gmtime, :utc
71
+
72
+ # Returns the underlying TZInfo::TimezonePeriod.
73
+ def period
74
+ @period ||= time_zone.period_for_utc(@utc)
75
+ end
76
+
77
+ # Returns the simultaneous time in <tt>Time.zone</tt>, or the specified zone.
78
+ def in_time_zone(new_zone = ::Time.zone)
79
+ return self if time_zone == new_zone
80
+ utc.in_time_zone(new_zone)
81
+ end
82
+
83
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
84
+ def localtime(utc_offset = nil)
85
+ utc.getlocal(utc_offset)
86
+ end
87
+ alias_method :getlocal, :localtime
88
+
89
+ # Returns true if the current time is within Daylight Savings Time for the
90
+ # specified time zone.
91
+ #
92
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
93
+ # Time.zone.parse("2012-5-30").dst? # => true
94
+ # Time.zone.parse("2012-11-30").dst? # => false
95
+ def dst?
96
+ period.dst?
97
+ end
98
+ alias_method :isdst, :dst?
99
+
100
+ # Returns true if the current time zone is set to UTC.
101
+ #
102
+ # Time.zone = 'UTC' # => 'UTC'
103
+ # Time.zone.now.utc? # => true
104
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
105
+ # Time.zone.now.utc? # => false
106
+ def utc?
107
+ period.offset.abbreviation == :UTC || period.offset.abbreviation == :UCT
108
+ end
109
+ alias_method :gmt?, :utc?
110
+
111
+ # Returns the offset from current time to UTC time in seconds.
112
+ def utc_offset
113
+ period.utc_total_offset
114
+ end
115
+ alias_method :gmt_offset, :utc_offset
116
+ alias_method :gmtoff, :utc_offset
117
+
118
+ # Returns a formatted string of the offset from UTC, or an alternative
119
+ # string if the time zone is already UTC.
120
+ #
121
+ # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
122
+ # Time.zone.now.formatted_offset(true) # => "-05:00"
123
+ # Time.zone.now.formatted_offset(false) # => "-0500"
124
+ # Time.zone = 'UTC' # => "UTC"
125
+ # Time.zone.now.formatted_offset(true, "0") # => "0"
126
+ def formatted_offset(colon = true, alternate_utc_string = nil)
127
+ utc? && alternate_utc_string || TimeZone.seconds_to_utc_offset(utc_offset, colon)
128
+ end
129
+
130
+ # Returns the time zone abbreviation.
131
+ #
132
+ # Time.zone = 'Eastern Time (US & Canada)' # => "Eastern Time (US & Canada)"
133
+ # Time.zone.now.zone # => "EST"
134
+ def zone
135
+ period.zone_identifier.to_s
136
+ end
137
+
138
+ # Returns a string of the object's date, time, zone, and offset from UTC.
139
+ #
140
+ # Time.zone.now.inspect # => "Thu, 04 Dec 2014 11:00:25 EST -05:00"
141
+ def inspect
142
+ "#{time.strftime('%a, %d %b %Y %H:%M:%S')} #{zone} #{formatted_offset}"
143
+ end
144
+
145
+ # Returns a string of the object's date and time in the ISO 8601 standard
146
+ # format.
147
+ #
148
+ # Time.zone.now.xmlschema # => "2014-12-04T11:02:37-05:00"
149
+ def xmlschema(fraction_digits = 0)
150
+ "#{time.strftime(PRECISIONS[fraction_digits.to_i])}#{formatted_offset(true, 'Z')}"
151
+ end
152
+ alias_method :iso8601, :xmlschema
153
+ alias_method :rfc3339, :xmlschema
154
+
155
+ # Coerces time to a string for JSON encoding. The default format is ISO 8601.
156
+ # You can get %Y/%m/%d %H:%M:%S +offset style by setting
157
+ # <tt>ActiveSupport::JSON::Encoding.use_standard_json_time_format</tt>
158
+ # to +false+.
159
+ #
160
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
161
+ # Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").to_json
162
+ # # => "2005-02-01T05:15:10.000-10:00"
163
+ #
164
+ # # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
165
+ # Time.utc(2005,2,1,15,15,10).in_time_zone("Hawaii").to_json
166
+ # # => "2005/02/01 05:15:10 -1000"
167
+ def as_json(options = nil)
168
+ if ActiveSupport::JSON::Encoding.use_standard_json_time_format
169
+ xmlschema(ActiveSupport::JSON::Encoding.time_precision)
170
+ else
171
+ %(#{time.strftime("%Y/%m/%d %H:%M:%S")} #{formatted_offset(false)})
172
+ end
173
+ end
174
+
175
+ def init_with(coder) #:nodoc:
176
+ initialize(coder["utc"], coder["zone"], coder["time"])
177
+ end
178
+
179
+ def encode_with(coder) #:nodoc:
180
+ coder.tag = "!ruby/object:ActiveSupport::TimeWithZone"
181
+ coder.map = { "utc" => utc, "zone" => time_zone, "time" => time }
182
+ end
183
+
184
+ # Returns a string of the object's date and time in the format used by
185
+ # HTTP requests.
186
+ #
187
+ # Time.zone.now.httpdate # => "Tue, 01 Jan 2013 04:39:43 GMT"
188
+ def httpdate
189
+ utc.httpdate
190
+ end
191
+
192
+ # Returns a string of the object's date and time in the RFC 2822 standard
193
+ # format.
194
+ #
195
+ # Time.zone.now.rfc2822 # => "Tue, 01 Jan 2013 04:51:39 +0000"
196
+ def rfc2822
197
+ to_s(:rfc822)
198
+ end
199
+ alias_method :rfc822, :rfc2822
200
+
201
+ # Returns a string of the object's date and time.
202
+ # Accepts an optional <tt>format</tt>:
203
+ # * <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).
205
+ # * 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)
207
+ if format == :db
208
+ utc.to_s(format)
209
+ elsif formatter = ::Time::DATE_FORMATS[format]
210
+ formatter.respond_to?(:call) ? formatter.call(self).to_s : strftime(formatter)
211
+ else
212
+ "#{time.strftime("%Y-%m-%d %H:%M:%S")} #{formatted_offset(false, 'UTC')}" # mimicking Ruby Time#to_s format
213
+ end
214
+ end
215
+ alias_method :to_formatted_s, :to_s
216
+
217
+ # Replaces <tt>%Z</tt> directive with +zone before passing to Time#strftime,
218
+ # so that zone information is correct.
219
+ def strftime(format)
220
+ format = format.gsub(/((?:\A|[^%])(?:%%)*)%Z/, "\\1#{zone}")
221
+ getlocal(utc_offset).strftime(format)
222
+ end
223
+
224
+ # Use the time in UTC for comparisons.
225
+ def <=>(other)
226
+ utc <=> other
227
+ end
228
+ alias_method :before?, :<
229
+ alias_method :after?, :>
230
+
231
+ # Returns true if the current object's time is within the specified
232
+ # +min+ and +max+ time.
233
+ def between?(min, max)
234
+ utc.between?(min, max)
235
+ end
236
+
237
+ # Returns true if the current object's time is in the past.
238
+ def past?
239
+ utc.past?
240
+ end
241
+
242
+ # Returns true if the current object's time falls within
243
+ # the current day.
244
+ def today?
245
+ time.today?
246
+ end
247
+
248
+ # Returns true if the current object's time is in the future.
249
+ def future?
250
+ utc.future?
251
+ end
252
+
253
+ # Returns +true+ if +other+ is equal to current object.
254
+ def eql?(other)
255
+ other.eql?(utc)
256
+ end
257
+
258
+ def hash
259
+ utc.hash
260
+ end
261
+
262
+ # Adds an interval of time to the current object's time and returns that
263
+ # value as a new TimeWithZone object.
264
+ #
265
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
266
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
267
+ # now + 1000 # => Sun, 02 Nov 2014 01:43:08 EDT -04:00
268
+ #
269
+ # If we're adding a Duration of variable length (i.e., years, months, days),
270
+ # move forward from #time, otherwise move forward from #utc, for accuracy
271
+ # when moving across DST boundaries.
272
+ #
273
+ # For instance, a time + 24.hours will advance exactly 24 hours, while a
274
+ # time + 1.day will advance 23-25 hours, depending on the day.
275
+ #
276
+ # now + 24.hours # => Mon, 03 Nov 2014 00:26:28 EST -05:00
277
+ # now + 1.day # => Mon, 03 Nov 2014 01:26:28 EST -05:00
278
+ def +(other)
279
+ if duration_of_variable_length?(other)
280
+ method_missing(:+, other)
281
+ else
282
+ result = utc.acts_like?(:date) ? utc.since(other) : utc + other rescue utc.since(other)
283
+ result.in_time_zone(time_zone)
284
+ end
285
+ end
286
+ alias_method :since, :+
287
+ alias_method :in, :+
288
+
289
+ # Subtracts an interval of time and returns a new TimeWithZone object unless
290
+ # the other value `acts_like?` time. Then it will return a Float of the difference
291
+ # between the two times that represents the difference between the current
292
+ # object's time and the +other+ time.
293
+ #
294
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
295
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
296
+ # now - 1000 # => Mon, 03 Nov 2014 00:09:48 EST -05:00
297
+ #
298
+ # If subtracting a Duration of variable length (i.e., years, months, days),
299
+ # move backward from #time, otherwise move backward from #utc, for accuracy
300
+ # when moving across DST boundaries.
301
+ #
302
+ # For instance, a time - 24.hours will go subtract exactly 24 hours, while a
303
+ # time - 1.day will subtract 23-25 hours, depending on the day.
304
+ #
305
+ # now - 24.hours # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
306
+ # now - 1.day # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
307
+ #
308
+ # If both the TimeWithZone object and the other value act like Time, a Float
309
+ # will be returned.
310
+ #
311
+ # Time.zone.now - 1.day.ago # => 86399.999967
312
+ #
313
+ def -(other)
314
+ if other.acts_like?(:time)
315
+ to_time - other.to_time
316
+ elsif duration_of_variable_length?(other)
317
+ method_missing(:-, other)
318
+ else
319
+ result = utc.acts_like?(:date) ? utc.ago(other) : utc - other rescue utc.ago(other)
320
+ result.in_time_zone(time_zone)
321
+ end
322
+ end
323
+
324
+ # Subtracts an interval of time from the current object's time and returns
325
+ # the result as a new TimeWithZone object.
326
+ #
327
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
328
+ # now = Time.zone.now # => Mon, 03 Nov 2014 00:26:28 EST -05:00
329
+ # now.ago(1000) # => Mon, 03 Nov 2014 00:09:48 EST -05:00
330
+ #
331
+ # If we're subtracting a Duration of variable length (i.e., years, months,
332
+ # days), move backward from #time, otherwise move backward from #utc, for
333
+ # accuracy when moving across DST boundaries.
334
+ #
335
+ # For instance, <tt>time.ago(24.hours)</tt> will move back exactly 24 hours,
336
+ # while <tt>time.ago(1.day)</tt> will move back 23-25 hours, depending on
337
+ # the day.
338
+ #
339
+ # now.ago(24.hours) # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
340
+ # now.ago(1.day) # => Sun, 02 Nov 2014 00:26:28 EDT -04:00
341
+ def ago(other)
342
+ since(-other)
343
+ end
344
+
345
+ # Returns a new +ActiveSupport::TimeWithZone+ where one or more of the elements have
346
+ # been changed according to the +options+ parameter. The time options (<tt>:hour</tt>,
347
+ # <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>, <tt>:nsec</tt>) reset cascadingly,
348
+ # so if only the hour is passed, then minute, sec, usec and nsec is set to 0. If the
349
+ # hour and minute is passed, then sec, usec and nsec is set to 0. The +options+
350
+ # parameter takes a hash with any of these keys: <tt>:year</tt>, <tt>:month</tt>,
351
+ # <tt>:day</tt>, <tt>:hour</tt>, <tt>:min</tt>, <tt>:sec</tt>, <tt>:usec</tt>,
352
+ # <tt>:nsec</tt>, <tt>:offset</tt>, <tt>:zone</tt>. Pass either <tt>:usec</tt>
353
+ # or <tt>:nsec</tt>, not both. Similarly, pass either <tt>:zone</tt> or
354
+ # <tt>:offset</tt>, not both.
355
+ #
356
+ # t = Time.zone.now # => Fri, 14 Apr 2017 11:45:15 EST -05:00
357
+ # t.change(year: 2020) # => Tue, 14 Apr 2020 11:45:15 EST -05:00
358
+ # t.change(hour: 12) # => Fri, 14 Apr 2017 12:00:00 EST -05:00
359
+ # t.change(min: 30) # => Fri, 14 Apr 2017 11:30:00 EST -05:00
360
+ # t.change(offset: "-10:00") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
361
+ # t.change(zone: "Hawaii") # => Fri, 14 Apr 2017 11:45:15 HST -10:00
362
+ def change(options)
363
+ if options[:zone] && options[:offset]
364
+ raise ArgumentError, "Can't change both :offset and :zone at the same time: #{options.inspect}"
365
+ end
366
+
367
+ new_time = time.change(options)
368
+
369
+ if options[:zone]
370
+ new_zone = ::Time.find_zone(options[:zone])
371
+ elsif options[:offset]
372
+ new_zone = ::Time.find_zone(new_time.utc_offset)
373
+ end
374
+
375
+ new_zone ||= time_zone
376
+ periods = new_zone.periods_for_local(new_time)
377
+
378
+ self.class.new(nil, new_zone, new_time, periods.include?(period) ? period : nil)
379
+ end
380
+
381
+ # Uses Date to provide precise Time calculations for years, months, and days
382
+ # according to the proleptic Gregorian calendar. The result is returned as a
383
+ # new TimeWithZone object.
384
+ #
385
+ # The +options+ parameter takes a hash with any of these keys:
386
+ # <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>,
387
+ # <tt>:hours</tt>, <tt>:minutes</tt>, <tt>:seconds</tt>.
388
+ #
389
+ # If advancing by a value of variable length (i.e., years, weeks, months,
390
+ # days), move forward from #time, otherwise move forward from #utc, for
391
+ # accuracy when moving across DST boundaries.
392
+ #
393
+ # Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
394
+ # now = Time.zone.now # => Sun, 02 Nov 2014 01:26:28 EDT -04:00
395
+ # now.advance(seconds: 1) # => Sun, 02 Nov 2014 01:26:29 EDT -04:00
396
+ # now.advance(minutes: 1) # => Sun, 02 Nov 2014 01:27:28 EDT -04:00
397
+ # now.advance(hours: 1) # => Sun, 02 Nov 2014 01:26:28 EST -05:00
398
+ # now.advance(days: 1) # => Mon, 03 Nov 2014 01:26:28 EST -05:00
399
+ # now.advance(weeks: 1) # => Sun, 09 Nov 2014 01:26:28 EST -05:00
400
+ # now.advance(months: 1) # => Tue, 02 Dec 2014 01:26:28 EST -05:00
401
+ # now.advance(years: 1) # => Mon, 02 Nov 2015 01:26:28 EST -05:00
402
+ def advance(options)
403
+ # If we're advancing a value of variable length (i.e., years, weeks, months, days), advance from #time,
404
+ # otherwise advance from #utc, for accuracy when moving across DST boundaries
405
+ if options.values_at(:years, :weeks, :months, :days).any?
406
+ method_missing(:advance, options)
407
+ else
408
+ utc.advance(options).in_time_zone(time_zone)
409
+ end
410
+ end
411
+
412
+ %w(year mon month day mday wday yday hour min sec usec nsec to_date).each do |method_name|
413
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
414
+ def #{method_name} # def month
415
+ time.#{method_name} # time.month
416
+ end # end
417
+ EOV
418
+ end
419
+
420
+ # Returns Array of parts of Time in sequence of
421
+ # [seconds, minutes, hours, day, month, year, weekday, yearday, dst?, zone].
422
+ #
423
+ # now = Time.zone.now # => Tue, 18 Aug 2015 02:29:27 UTC +00:00
424
+ # now.to_a # => [27, 29, 2, 18, 8, 2015, 2, 230, false, "UTC"]
425
+ def to_a
426
+ [time.sec, time.min, time.hour, time.day, time.mon, time.year, time.wday, time.yday, dst?, zone]
427
+ end
428
+
429
+ # Returns the object's date and time as a floating point number of seconds
430
+ # since the Epoch (January 1, 1970 00:00 UTC).
431
+ #
432
+ # Time.zone.now.to_f # => 1417709320.285418
433
+ def to_f
434
+ utc.to_f
435
+ end
436
+
437
+ # Returns the object's date and time as an integer number of seconds
438
+ # since the Epoch (January 1, 1970 00:00 UTC).
439
+ #
440
+ # Time.zone.now.to_i # => 1417709320
441
+ def to_i
442
+ utc.to_i
443
+ end
444
+ alias_method :tv_sec, :to_i
445
+
446
+ # Returns the object's date and time as a rational number of seconds
447
+ # since the Epoch (January 1, 1970 00:00 UTC).
448
+ #
449
+ # Time.zone.now.to_r # => (708854548642709/500000)
450
+ def to_r
451
+ utc.to_r
452
+ end
453
+
454
+ # Returns an instance of DateTime with the timezone's UTC offset
455
+ #
456
+ # Time.zone.now.to_datetime # => Tue, 18 Aug 2015 02:32:20 +0000
457
+ # Time.current.in_time_zone('Hawaii').to_datetime # => Mon, 17 Aug 2015 16:32:20 -1000
458
+ def to_datetime
459
+ @to_datetime ||= utc.to_datetime.new_offset(Rational(utc_offset, 86_400))
460
+ end
461
+
462
+ # Returns an instance of +Time+, either with the same UTC offset
463
+ # as +self+ or in the local system timezone depending on the setting
464
+ # of +ActiveSupport.to_time_preserves_timezone+.
465
+ def to_time
466
+ if preserve_timezone
467
+ @to_time_with_instance_offset ||= getlocal(utc_offset)
468
+ else
469
+ @to_time_with_system_offset ||= getlocal
470
+ end
471
+ end
472
+
473
+ # So that +self+ <tt>acts_like?(:time)</tt>.
474
+ def acts_like_time?
475
+ true
476
+ end
477
+
478
+ # Say we're a Time to thwart type checking.
479
+ def is_a?(klass)
480
+ klass == ::Time || super
481
+ end
482
+ alias_method :kind_of?, :is_a?
483
+
484
+ # An instance of ActiveSupport::TimeWithZone is never blank
485
+ def blank?
486
+ false
487
+ end
488
+
489
+ def freeze
490
+ # preload instance variables before freezing
491
+ period; utc; time; to_datetime; to_time
492
+ super
493
+ end
494
+
495
+ def marshal_dump
496
+ [utc, time_zone.name, time]
497
+ end
498
+
499
+ def marshal_load(variables)
500
+ initialize(variables[0].utc, ::Time.find_zone(variables[1]), variables[2].utc)
501
+ end
502
+
503
+ # respond_to_missing? is not called in some cases, such as when type conversion is
504
+ # performed with Kernel#String
505
+ def respond_to?(sym, include_priv = false)
506
+ # ensure that we're not going to throw and rescue from NoMethodError in method_missing which is slow
507
+ return false if sym.to_sym == :to_str
508
+ super
509
+ end
510
+
511
+ # Ensure proxy class responds to all methods that underlying time instance
512
+ # responds to.
513
+ def respond_to_missing?(sym, include_priv)
514
+ return false if sym.to_sym == :acts_like_date?
515
+ time.respond_to?(sym, include_priv)
516
+ end
517
+
518
+ # Send the missing method to +time+ instance, and wrap result in a new
519
+ # TimeWithZone with the existing +time_zone+.
520
+ def method_missing(sym, *args, &block)
521
+ wrap_with_time_zone time.__send__(sym, *args, &block)
522
+ rescue NoMethodError => e
523
+ raise e, e.message.sub(time.inspect, inspect), e.backtrace
524
+ end
525
+
526
+ private
527
+ def get_period_and_ensure_valid_local_time(period)
528
+ # we don't want a Time.local instance enforcing its own DST rules as well,
529
+ # so transfer time values to a utc constructor if necessary
530
+ @time = transfer_time_values_to_utc_constructor(@time) unless @time.utc?
531
+ begin
532
+ period || @time_zone.period_for_local(@time)
533
+ rescue ::TZInfo::PeriodNotFound
534
+ # time is in the "spring forward" hour gap, so we're moving the time forward one hour and trying again
535
+ @time += 1.hour
536
+ retry
537
+ end
538
+ end
539
+
540
+ def transfer_time_values_to_utc_constructor(time)
541
+ # avoid creating another Time object if possible
542
+ return time if time.instance_of?(::Time) && time.utc?
543
+ ::Time.utc(time.year, time.month, time.day, time.hour, time.min, time.sec + time.subsec)
544
+ end
545
+
546
+ def duration_of_variable_length?(obj)
547
+ ActiveSupport::Duration === obj && obj.parts.any? { |p| [:years, :months, :weeks, :days].include?(p[0]) }
548
+ end
549
+
550
+ def wrap_with_time_zone(time)
551
+ if time.acts_like?(:time)
552
+ periods = time_zone.periods_for_local(time)
553
+ self.class.new(nil, time_zone, time, periods.include?(period) ? period : nil)
554
+ elsif time.is_a?(Range)
555
+ wrap_with_time_zone(time.begin)..wrap_with_time_zone(time.end)
556
+ else
557
+ time
558
+ end
559
+ end
560
+ end
561
+ end