activesupport 1.2.4 → 8.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (309) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +505 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +40 -0
  5. data/lib/active_support/actionable_error.rb +50 -0
  6. data/lib/active_support/all.rb +5 -0
  7. data/lib/active_support/array_inquirer.rb +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +234 -0
  9. data/lib/active_support/benchmark.rb +21 -0
  10. data/lib/active_support/benchmarkable.rb +53 -0
  11. data/lib/active_support/broadcast_logger.rb +238 -0
  12. data/lib/active_support/builder.rb +8 -0
  13. data/lib/active_support/cache/coder.rb +153 -0
  14. data/lib/active_support/cache/entry.rb +134 -0
  15. data/lib/active_support/cache/file_store.rb +244 -0
  16. data/lib/active_support/cache/mem_cache_store.rb +288 -0
  17. data/lib/active_support/cache/memory_store.rb +264 -0
  18. data/lib/active_support/cache/null_store.rb +62 -0
  19. data/lib/active_support/cache/redis_cache_store.rb +498 -0
  20. data/lib/active_support/cache/serializer_with_fallback.rb +152 -0
  21. data/lib/active_support/cache/strategy/local_cache.rb +246 -0
  22. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  23. data/lib/active_support/cache.rb +1170 -0
  24. data/lib/active_support/callbacks.rb +960 -0
  25. data/lib/active_support/class_attribute.rb +33 -0
  26. data/lib/active_support/code_generator.rb +79 -0
  27. data/lib/active_support/concern.rb +217 -0
  28. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  29. data/lib/active_support/concurrency/null_lock.rb +13 -0
  30. data/lib/active_support/concurrency/share_lock.rb +225 -0
  31. data/lib/active_support/concurrency/thread_monitor.rb +55 -0
  32. data/lib/active_support/configurable.rb +193 -0
  33. data/lib/active_support/configuration_file.rb +60 -0
  34. data/lib/active_support/continuous_integration.rb +145 -0
  35. data/lib/active_support/core_ext/array/access.rb +100 -0
  36. data/lib/active_support/core_ext/array/conversions.rb +209 -26
  37. data/lib/active_support/core_ext/array/extract.rb +21 -0
  38. data/lib/active_support/core_ext/array/extract_options.rb +31 -0
  39. data/lib/active_support/core_ext/array/grouping.rb +109 -0
  40. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  41. data/lib/active_support/core_ext/array/wrap.rb +48 -0
  42. data/lib/active_support/core_ext/array.rb +8 -4
  43. data/lib/active_support/core_ext/benchmark.rb +6 -0
  44. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  45. data/lib/active_support/core_ext/big_decimal.rb +3 -0
  46. data/lib/active_support/core_ext/class/attribute.rb +137 -0
  47. data/lib/active_support/core_ext/class/attribute_accessors.rb +6 -0
  48. data/lib/active_support/core_ext/class/subclasses.rb +24 -0
  49. data/lib/active_support/core_ext/class.rb +4 -0
  50. data/lib/active_support/core_ext/date/acts_like.rb +10 -0
  51. data/lib/active_support/core_ext/date/blank.rb +18 -0
  52. data/lib/active_support/core_ext/date/calculations.rb +161 -0
  53. data/lib/active_support/core_ext/date/conversions.rb +95 -28
  54. data/lib/active_support/core_ext/date/zones.rb +8 -0
  55. data/lib/active_support/core_ext/date.rb +6 -5
  56. data/lib/active_support/core_ext/date_and_time/calculations.rb +374 -0
  57. data/lib/active_support/core_ext/date_and_time/compatibility.rb +23 -0
  58. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  59. data/lib/active_support/core_ext/date_time/acts_like.rb +16 -0
  60. data/lib/active_support/core_ext/date_time/blank.rb +18 -0
  61. data/lib/active_support/core_ext/date_time/calculations.rb +215 -0
  62. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  63. data/lib/active_support/core_ext/date_time/conversions.rb +108 -0
  64. data/lib/active_support/core_ext/date_time.rb +7 -0
  65. data/lib/active_support/core_ext/digest/uuid.rb +76 -0
  66. data/lib/active_support/core_ext/digest.rb +3 -0
  67. data/lib/active_support/core_ext/enumerable.rb +277 -7
  68. data/lib/active_support/core_ext/erb/util.rb +201 -0
  69. data/lib/active_support/core_ext/file/atomic.rb +72 -0
  70. data/lib/active_support/core_ext/file.rb +3 -0
  71. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  72. data/lib/active_support/core_ext/hash/deep_merge.rb +43 -0
  73. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  74. data/lib/active_support/core_ext/hash/except.rb +12 -0
  75. data/lib/active_support/core_ext/hash/indifferent_access.rb +19 -55
  76. data/lib/active_support/core_ext/hash/keys.rb +134 -44
  77. data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -22
  78. data/lib/active_support/core_ext/hash/slice.rb +27 -0
  79. data/lib/active_support/core_ext/hash.rb +9 -8
  80. data/lib/active_support/core_ext/integer/inflections.rb +29 -13
  81. data/lib/active_support/core_ext/integer/multiple.rb +12 -0
  82. data/lib/active_support/core_ext/integer/time.rb +22 -0
  83. data/lib/active_support/core_ext/integer.rb +4 -6
  84. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  85. data/lib/active_support/core_ext/kernel/reporting.rb +45 -0
  86. data/lib/active_support/core_ext/kernel/singleton_class.rb +8 -0
  87. data/lib/active_support/core_ext/kernel.rb +4 -78
  88. data/lib/active_support/core_ext/load_error.rb +6 -35
  89. data/lib/active_support/core_ext/module/aliasing.rb +31 -0
  90. data/lib/active_support/core_ext/module/anonymous.rb +30 -0
  91. data/lib/active_support/core_ext/module/attr_internal.rb +48 -0
  92. data/lib/active_support/core_ext/module/attribute_accessors.rb +214 -0
  93. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +175 -0
  94. data/lib/active_support/core_ext/module/concerning.rb +140 -0
  95. data/lib/active_support/core_ext/module/delegation.rb +225 -0
  96. data/lib/active_support/core_ext/module/deprecation.rb +25 -0
  97. data/lib/active_support/core_ext/module/introspection.rb +65 -0
  98. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  99. data/lib/active_support/core_ext/module/remove_method.rb +17 -0
  100. data/lib/active_support/core_ext/module.rb +13 -0
  101. data/lib/active_support/core_ext/name_error.rb +59 -0
  102. data/lib/active_support/core_ext/numeric/bytes.rb +73 -42
  103. data/lib/active_support/core_ext/numeric/conversions.rb +145 -0
  104. data/lib/active_support/core_ext/numeric/time.rb +64 -57
  105. data/lib/active_support/core_ext/numeric.rb +4 -6
  106. data/lib/active_support/core_ext/object/acts_like.rb +45 -0
  107. data/lib/active_support/core_ext/object/blank.rb +199 -0
  108. data/lib/active_support/core_ext/object/conversions.rb +6 -0
  109. data/lib/active_support/core_ext/object/deep_dup.rb +71 -0
  110. data/lib/active_support/core_ext/object/duplicable.rb +69 -0
  111. data/lib/active_support/core_ext/object/inclusion.rb +37 -0
  112. data/lib/active_support/core_ext/object/instance_variables.rb +32 -0
  113. data/lib/active_support/core_ext/object/json.rb +267 -0
  114. data/lib/active_support/core_ext/object/to_param.rb +3 -0
  115. data/lib/active_support/core_ext/object/to_query.rb +93 -0
  116. data/lib/active_support/core_ext/object/try.rb +158 -0
  117. data/lib/active_support/core_ext/object/with.rb +46 -0
  118. data/lib/active_support/core_ext/object/with_options.rb +101 -0
  119. data/lib/active_support/core_ext/object.rb +17 -0
  120. data/lib/active_support/core_ext/pathname/blank.rb +20 -0
  121. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  122. data/lib/active_support/core_ext/pathname.rb +4 -0
  123. data/lib/active_support/core_ext/range/compare_range.rb +57 -0
  124. data/lib/active_support/core_ext/range/conversions.rb +58 -17
  125. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  126. data/lib/active_support/core_ext/range/sole.rb +17 -0
  127. data/lib/active_support/core_ext/range.rb +5 -4
  128. data/lib/active_support/core_ext/regexp.rb +14 -0
  129. data/lib/active_support/core_ext/securerandom.rb +57 -0
  130. data/lib/active_support/core_ext/string/access.rb +93 -56
  131. data/lib/active_support/core_ext/string/behavior.rb +8 -0
  132. data/lib/active_support/core_ext/string/conversions.rb +57 -16
  133. data/lib/active_support/core_ext/string/exclude.rb +13 -0
  134. data/lib/active_support/core_ext/string/filters.rb +151 -0
  135. data/lib/active_support/core_ext/string/indent.rb +45 -0
  136. data/lib/active_support/core_ext/string/inflections.rb +297 -54
  137. data/lib/active_support/core_ext/string/inquiry.rb +16 -0
  138. data/lib/active_support/core_ext/string/multibyte.rb +67 -0
  139. data/lib/active_support/core_ext/string/output_safety.rb +235 -0
  140. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -18
  141. data/lib/active_support/core_ext/string/strip.rb +27 -0
  142. data/lib/active_support/core_ext/string/zones.rb +16 -0
  143. data/lib/active_support/core_ext/string.rb +14 -10
  144. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  145. data/lib/active_support/core_ext/symbol.rb +3 -0
  146. data/lib/active_support/core_ext/thread/backtrace/location.rb +7 -0
  147. data/lib/active_support/core_ext/time/acts_like.rb +10 -0
  148. data/lib/active_support/core_ext/time/calculations.rb +358 -153
  149. data/lib/active_support/core_ext/time/compatibility.rb +15 -0
  150. data/lib/active_support/core_ext/time/conversions.rb +69 -30
  151. data/lib/active_support/core_ext/time/zones.rb +97 -0
  152. data/lib/active_support/core_ext/time.rb +6 -6
  153. data/lib/active_support/core_ext.rb +5 -1
  154. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  155. data/lib/active_support/current_attributes.rb +243 -0
  156. data/lib/active_support/deep_mergeable.rb +53 -0
  157. data/lib/active_support/delegation.rb +183 -0
  158. data/lib/active_support/dependencies/autoload.rb +72 -0
  159. data/lib/active_support/dependencies/interlock.rb +55 -0
  160. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  161. data/lib/active_support/dependencies.rb +84 -222
  162. data/lib/active_support/deprecation/behaviors.rb +148 -0
  163. data/lib/active_support/deprecation/constant_accessor.rb +74 -0
  164. data/lib/active_support/deprecation/deprecators.rb +104 -0
  165. data/lib/active_support/deprecation/disallowed.rb +54 -0
  166. data/lib/active_support/deprecation/method_wrappers.rb +68 -0
  167. data/lib/active_support/deprecation/proxy_wrappers.rb +189 -0
  168. data/lib/active_support/deprecation/reporting.rb +162 -0
  169. data/lib/active_support/deprecation.rb +81 -0
  170. data/lib/active_support/deprecator.rb +7 -0
  171. data/lib/active_support/descendants_tracker.rb +112 -0
  172. data/lib/active_support/digest.rb +22 -0
  173. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  174. data/lib/active_support/duration/iso8601_serializer.rb +64 -0
  175. data/lib/active_support/duration.rb +524 -0
  176. data/lib/active_support/editor.rb +70 -0
  177. data/lib/active_support/encrypted_configuration.rb +126 -0
  178. data/lib/active_support/encrypted_file.rb +133 -0
  179. data/lib/active_support/environment_inquirer.rb +40 -0
  180. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  181. data/lib/active_support/error_reporter.rb +318 -0
  182. data/lib/active_support/event_reporter/test_helper.rb +32 -0
  183. data/lib/active_support/event_reporter.rb +592 -0
  184. data/lib/active_support/evented_file_update_checker.rb +185 -0
  185. data/lib/active_support/execution_context/test_helper.rb +13 -0
  186. data/lib/active_support/execution_context.rb +110 -0
  187. data/lib/active_support/execution_wrapper.rb +150 -0
  188. data/lib/active_support/executor/test_helper.rb +7 -0
  189. data/lib/active_support/executor.rb +8 -0
  190. data/lib/active_support/file_update_checker.rb +166 -0
  191. data/lib/active_support/fork_tracker.rb +43 -0
  192. data/lib/active_support/gem_version.rb +17 -0
  193. data/lib/active_support/gzip.rb +41 -0
  194. data/lib/active_support/hash_with_indifferent_access.rb +464 -0
  195. data/lib/active_support/html_safe_translation.rb +56 -0
  196. data/lib/active_support/i18n.rb +17 -0
  197. data/lib/active_support/i18n_railtie.rb +140 -0
  198. data/lib/active_support/inflections.rb +68 -49
  199. data/lib/active_support/inflector/inflections.rb +290 -0
  200. data/lib/active_support/inflector/methods.rb +387 -0
  201. data/lib/active_support/inflector/transliterate.rb +147 -0
  202. data/lib/active_support/inflector.rb +7 -164
  203. data/lib/active_support/isolated_execution_state.rb +76 -0
  204. data/lib/active_support/json/decoding.rb +78 -0
  205. data/lib/active_support/json/encoding.rb +256 -0
  206. data/lib/active_support/json.rb +4 -0
  207. data/lib/active_support/key_generator.rb +66 -0
  208. data/lib/active_support/lazy_load_hooks.rb +107 -0
  209. data/lib/active_support/locale/en.rb +33 -0
  210. data/lib/active_support/locale/en.yml +141 -0
  211. data/lib/active_support/log_subscriber/test_helper.rb +106 -0
  212. data/lib/active_support/log_subscriber.rb +188 -0
  213. data/lib/active_support/logger.rb +55 -0
  214. data/lib/active_support/logger_silence.rb +21 -0
  215. data/lib/active_support/logger_thread_safe_level.rb +50 -0
  216. data/lib/active_support/message_encryptor.rb +374 -0
  217. data/lib/active_support/message_encryptors.rb +193 -0
  218. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  219. data/lib/active_support/message_pack/extensions.rb +310 -0
  220. data/lib/active_support/message_pack/serializer.rb +63 -0
  221. data/lib/active_support/message_pack.rb +50 -0
  222. data/lib/active_support/message_verifier.rb +377 -0
  223. data/lib/active_support/message_verifiers.rb +189 -0
  224. data/lib/active_support/messages/codec.rb +65 -0
  225. data/lib/active_support/messages/metadata.rb +146 -0
  226. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  227. data/lib/active_support/messages/rotation_coordinator.rb +102 -0
  228. data/lib/active_support/messages/rotator.rb +69 -0
  229. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  230. data/lib/active_support/multibyte/chars.rb +188 -0
  231. data/lib/active_support/multibyte/unicode.rb +42 -0
  232. data/lib/active_support/multibyte.rb +27 -0
  233. data/lib/active_support/notifications/fanout.rb +467 -0
  234. data/lib/active_support/notifications/instrumenter.rb +240 -0
  235. data/lib/active_support/notifications.rb +281 -0
  236. data/lib/active_support/number_helper/number_converter.rb +190 -0
  237. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  238. data/lib/active_support/number_helper/number_to_delimited_converter.rb +30 -0
  239. data/lib/active_support/number_helper/number_to_human_converter.rb +69 -0
  240. data/lib/active_support/number_helper/number_to_human_size_converter.rb +60 -0
  241. data/lib/active_support/number_helper/number_to_percentage_converter.rb +16 -0
  242. data/lib/active_support/number_helper/number_to_phone_converter.rb +60 -0
  243. data/lib/active_support/number_helper/number_to_rounded_converter.rb +59 -0
  244. data/lib/active_support/number_helper/rounding_helper.rb +46 -0
  245. data/lib/active_support/number_helper.rb +479 -0
  246. data/lib/active_support/option_merger.rb +38 -0
  247. data/lib/active_support/ordered_hash.rb +50 -0
  248. data/lib/active_support/ordered_options.rb +141 -25
  249. data/lib/active_support/parameter_filter.rb +157 -0
  250. data/lib/active_support/rails.rb +26 -0
  251. data/lib/active_support/railtie.rb +180 -0
  252. data/lib/active_support/reloader.rb +138 -0
  253. data/lib/active_support/rescuable.rb +176 -0
  254. data/lib/active_support/secure_compare_rotator.rb +58 -0
  255. data/lib/active_support/security_utils.rb +38 -0
  256. data/lib/active_support/string_inquirer.rb +35 -0
  257. data/lib/active_support/structured_event_subscriber.rb +99 -0
  258. data/lib/active_support/subscriber.rb +141 -0
  259. data/lib/active_support/syntax_error_proxy.rb +67 -0
  260. data/lib/active_support/tagged_logging.rb +157 -0
  261. data/lib/active_support/test_case.rb +365 -0
  262. data/lib/active_support/testing/assertions.rb +369 -0
  263. data/lib/active_support/testing/autorun.rb +10 -0
  264. data/lib/active_support/testing/constant_lookup.rb +51 -0
  265. data/lib/active_support/testing/constant_stubbing.rb +54 -0
  266. data/lib/active_support/testing/declarative.rb +28 -0
  267. data/lib/active_support/testing/deprecation.rb +82 -0
  268. data/lib/active_support/testing/error_reporter_assertions.rb +124 -0
  269. data/lib/active_support/testing/event_reporter_assertions.rb +227 -0
  270. data/lib/active_support/testing/file_fixtures.rb +38 -0
  271. data/lib/active_support/testing/isolation.rb +121 -0
  272. data/lib/active_support/testing/method_call_assertions.rb +69 -0
  273. data/lib/active_support/testing/notification_assertions.rb +92 -0
  274. data/lib/active_support/testing/parallelization/server.rb +98 -0
  275. data/lib/active_support/testing/parallelization/worker.rb +107 -0
  276. data/lib/active_support/testing/parallelization.rb +79 -0
  277. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  278. data/lib/active_support/testing/setup_and_teardown.rb +57 -0
  279. data/lib/active_support/testing/stream.rb +41 -0
  280. data/lib/active_support/testing/tagged_logging.rb +27 -0
  281. data/lib/active_support/testing/tests_without_assertions.rb +19 -0
  282. data/lib/active_support/testing/time_helpers.rb +273 -0
  283. data/lib/active_support/time.rb +20 -0
  284. data/lib/active_support/time_with_zone.rb +613 -0
  285. data/lib/active_support/values/time_zone.rb +599 -158
  286. data/lib/active_support/version.rb +7 -6
  287. data/lib/active_support/xml_mini/jdom.rb +175 -0
  288. data/lib/active_support/xml_mini/libxml.rb +80 -0
  289. data/lib/active_support/xml_mini/libxmlsax.rb +83 -0
  290. data/lib/active_support/xml_mini/nokogiri.rb +83 -0
  291. data/lib/active_support/xml_mini/nokogirisax.rb +86 -0
  292. data/lib/active_support/xml_mini/rexml.rb +137 -0
  293. data/lib/active_support/xml_mini.rb +212 -0
  294. data/lib/active_support.rb +122 -10
  295. metadata +524 -93
  296. data/CHANGELOG +0 -283
  297. data/lib/active_support/binding_of_caller.rb +0 -84
  298. data/lib/active_support/breakpoint.rb +0 -523
  299. data/lib/active_support/class_attribute_accessors.rb +0 -57
  300. data/lib/active_support/class_inheritable_attributes.rb +0 -117
  301. data/lib/active_support/clean_logger.rb +0 -36
  302. data/lib/active_support/core_ext/blank.rb +0 -38
  303. data/lib/active_support/core_ext/cgi/escape_skipping_slashes.rb +0 -14
  304. data/lib/active_support/core_ext/cgi.rb +0 -5
  305. data/lib/active_support/core_ext/exception.rb +0 -29
  306. data/lib/active_support/core_ext/integer/even_odd.rb +0 -24
  307. data/lib/active_support/core_ext/object_and_class.rb +0 -44
  308. data/lib/active_support/module_attribute_accessors.rb +0 -57
  309. data/lib/active_support/whiny_nil.rb +0 -38
@@ -0,0 +1,374 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/try"
4
+ require "active_support/core_ext/date_time/conversions"
5
+
6
+ module DateAndTime
7
+ module Calculations
8
+ DAYS_INTO_WEEK = {
9
+ sunday: 0,
10
+ monday: 1,
11
+ tuesday: 2,
12
+ wednesday: 3,
13
+ thursday: 4,
14
+ friday: 5,
15
+ saturday: 6
16
+ }
17
+ WEEKEND_DAYS = [ 6, 0 ]
18
+
19
+ # Returns a new date/time representing yesterday.
20
+ def yesterday
21
+ advance(days: -1)
22
+ end
23
+
24
+ # Returns a new date/time representing tomorrow.
25
+ def tomorrow
26
+ advance(days: 1)
27
+ end
28
+
29
+ # Returns true if the date/time is today.
30
+ def today?
31
+ to_date == ::Date.current
32
+ end
33
+
34
+ # Returns true if the date/time is tomorrow.
35
+ def tomorrow?
36
+ to_date == ::Date.current.tomorrow
37
+ end
38
+ alias :next_day? :tomorrow?
39
+
40
+ # Returns true if the date/time is yesterday.
41
+ def yesterday?
42
+ to_date == ::Date.current.yesterday
43
+ end
44
+ alias :prev_day? :yesterday?
45
+
46
+ # Returns true if the date/time is in the past.
47
+ def past?
48
+ self < self.class.current
49
+ end
50
+
51
+ # Returns true if the date/time is in the future.
52
+ def future?
53
+ self > self.class.current
54
+ end
55
+
56
+ # Returns true if the date/time falls on a Saturday or Sunday.
57
+ def on_weekend?
58
+ WEEKEND_DAYS.include?(wday)
59
+ end
60
+
61
+ # Returns true if the date/time does not fall on a Saturday or Sunday.
62
+ def on_weekday?
63
+ !WEEKEND_DAYS.include?(wday)
64
+ end
65
+
66
+ # Returns true if the date/time falls before <tt>date_or_time</tt>.
67
+ def before?(date_or_time)
68
+ self < date_or_time
69
+ end
70
+
71
+ # Returns true if the date/time falls after <tt>date_or_time</tt>.
72
+ def after?(date_or_time)
73
+ self > date_or_time
74
+ end
75
+
76
+ # Returns a new date/time the specified number of days ago.
77
+ def days_ago(days)
78
+ advance(days: -days)
79
+ end
80
+
81
+ # Returns a new date/time the specified number of days in the future.
82
+ def days_since(days)
83
+ advance(days: days)
84
+ end
85
+
86
+ # Returns a new date/time the specified number of weeks ago.
87
+ def weeks_ago(weeks)
88
+ advance(weeks: -weeks)
89
+ end
90
+
91
+ # Returns a new date/time the specified number of weeks in the future.
92
+ def weeks_since(weeks)
93
+ advance(weeks: weeks)
94
+ end
95
+
96
+ # Returns a new date/time the specified number of months ago.
97
+ def months_ago(months)
98
+ advance(months: -months)
99
+ end
100
+
101
+ # Returns a new date/time the specified number of months in the future.
102
+ def months_since(months)
103
+ advance(months: months)
104
+ end
105
+
106
+ # Returns a new date/time the specified number of years ago.
107
+ def years_ago(years)
108
+ advance(years: -years)
109
+ end
110
+
111
+ # Returns a new date/time the specified number of years in the future.
112
+ def years_since(years)
113
+ advance(years: years)
114
+ end
115
+
116
+ # Returns a new date/time at the start of the month.
117
+ #
118
+ # today = Date.today # => Thu, 18 Jun 2015
119
+ # today.beginning_of_month # => Mon, 01 Jun 2015
120
+ #
121
+ # +DateTime+ objects will have a time set to 0:00.
122
+ #
123
+ # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000
124
+ # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000
125
+ def beginning_of_month
126
+ first_hour(change(day: 1))
127
+ end
128
+ alias :at_beginning_of_month :beginning_of_month
129
+
130
+ # Returns a new date/time at the start of the quarter.
131
+ #
132
+ # today = Date.today # => Fri, 10 Jul 2015
133
+ # today.beginning_of_quarter # => Wed, 01 Jul 2015
134
+ #
135
+ # +DateTime+ objects will have a time set to 0:00.
136
+ #
137
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
138
+ # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
139
+ def beginning_of_quarter
140
+ first_quarter_month = month - (2 + month) % 3
141
+ beginning_of_month.change(month: first_quarter_month)
142
+ end
143
+ alias :at_beginning_of_quarter :beginning_of_quarter
144
+
145
+ # Returns a new date/time at the end of the quarter.
146
+ #
147
+ # today = Date.today # => Fri, 10 Jul 2015
148
+ # today.end_of_quarter # => Wed, 30 Sep 2015
149
+ #
150
+ # +DateTime+ objects will have a time set to 23:59:59.
151
+ #
152
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
153
+ # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
154
+ def end_of_quarter
155
+ last_quarter_month = month + (12 - month) % 3
156
+ beginning_of_month.change(month: last_quarter_month).end_of_month
157
+ end
158
+ alias :at_end_of_quarter :end_of_quarter
159
+
160
+ # Returns the quarter for a date/time.
161
+ #
162
+ # Date.new(2010, 1, 31).quarter # => 1
163
+ # Date.new(2010, 4, 12).quarter # => 2
164
+ # Date.new(2010, 9, 15).quarter # => 3
165
+ # Date.new(2010, 12, 25).quarter # => 4
166
+ def quarter
167
+ (month / 3.0).ceil
168
+ end
169
+
170
+ # Returns a new date/time at the beginning of the year.
171
+ #
172
+ # today = Date.today # => Fri, 10 Jul 2015
173
+ # today.beginning_of_year # => Thu, 01 Jan 2015
174
+ #
175
+ # +DateTime+ objects will have a time set to 0:00.
176
+ #
177
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
178
+ # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000
179
+ def beginning_of_year
180
+ change(month: 1).beginning_of_month
181
+ end
182
+ alias :at_beginning_of_year :beginning_of_year
183
+
184
+ # Returns a new date/time representing the given day in the next week.
185
+ #
186
+ # today = Date.today # => Thu, 07 May 2015
187
+ # today.next_week # => Mon, 11 May 2015
188
+ #
189
+ # The +given_day_in_next_week+ defaults to the beginning of the week
190
+ # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
191
+ # when set.
192
+ #
193
+ # today = Date.today # => Thu, 07 May 2015
194
+ # today.next_week(:friday) # => Fri, 15 May 2015
195
+ #
196
+ # +DateTime+ objects have their time set to 0:00 unless +same_time+ is true.
197
+ #
198
+ # now = DateTime.current # => Thu, 07 May 2015 13:31:16 +0000
199
+ # now.next_week # => Mon, 11 May 2015 00:00:00 +0000
200
+ def next_week(given_day_in_next_week = Date.beginning_of_week, same_time: false)
201
+ result = first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
202
+ same_time ? copy_time_to(result) : result
203
+ end
204
+
205
+ # Returns a new date/time representing the next weekday.
206
+ def next_weekday
207
+ if next_day.on_weekend?
208
+ next_week(:monday, same_time: true)
209
+ else
210
+ next_day
211
+ end
212
+ end
213
+
214
+ # Short-hand for <tt>months_since(3)</tt>.
215
+ def next_quarter
216
+ months_since(3)
217
+ end
218
+
219
+ # Returns a new date/time representing the given day in the previous week.
220
+ # Week is assumed to start on +start_day+, default is
221
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
222
+ # DateTime objects have their time set to 0:00 unless +same_time+ is true.
223
+ def prev_week(start_day = Date.beginning_of_week, same_time: false)
224
+ result = first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
225
+ same_time ? copy_time_to(result) : result
226
+ end
227
+ alias_method :last_week, :prev_week
228
+
229
+ # Returns a new date/time representing the previous weekday.
230
+ def prev_weekday
231
+ if prev_day.on_weekend?
232
+ copy_time_to(beginning_of_week(:friday))
233
+ else
234
+ prev_day
235
+ end
236
+ end
237
+ alias_method :last_weekday, :prev_weekday
238
+
239
+ # Short-hand for <tt>months_ago(1)</tt>.
240
+ def last_month
241
+ months_ago(1)
242
+ end
243
+
244
+ # Short-hand for <tt>months_ago(3)</tt>.
245
+ def prev_quarter
246
+ months_ago(3)
247
+ end
248
+ alias_method :last_quarter, :prev_quarter
249
+
250
+ # Short-hand for <tt>years_ago(1)</tt>.
251
+ def last_year
252
+ years_ago(1)
253
+ end
254
+
255
+ # Returns the number of days to the start of the week on the given day.
256
+ # Week is assumed to start on +start_day+, default is
257
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
258
+ def days_to_week_start(start_day = Date.beginning_of_week)
259
+ start_day_number = DAYS_INTO_WEEK.fetch(start_day)
260
+ (wday - start_day_number) % 7
261
+ end
262
+
263
+ # Returns a new date/time representing the start of this week on the given day.
264
+ # Week is assumed to start on +start_day+, default is
265
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
266
+ # +DateTime+ objects have their time set to 0:00.
267
+ def beginning_of_week(start_day = Date.beginning_of_week)
268
+ result = days_ago(days_to_week_start(start_day))
269
+ acts_like?(:time) ? result.midnight : result
270
+ end
271
+ alias :at_beginning_of_week :beginning_of_week
272
+
273
+ # Returns Monday of this week assuming that week starts on Monday.
274
+ # +DateTime+ objects have their time set to 0:00.
275
+ def monday
276
+ beginning_of_week(:monday)
277
+ end
278
+
279
+ # Returns a new date/time representing the end of this week on the given day.
280
+ # Week is assumed to start on +start_day+, default is
281
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
282
+ # DateTime objects have their time set to 23:59:59.
283
+ def end_of_week(start_day = Date.beginning_of_week)
284
+ last_hour(days_since(6 - days_to_week_start(start_day)))
285
+ end
286
+ alias :at_end_of_week :end_of_week
287
+
288
+ # Returns Sunday of this week assuming that week starts on Monday.
289
+ # +DateTime+ objects have their time set to 23:59:59.
290
+ def sunday
291
+ end_of_week(:monday)
292
+ end
293
+
294
+ # Returns a new date/time representing the end of the month.
295
+ # DateTime objects will have a time set to 23:59:59.
296
+ def end_of_month
297
+ last_day = ::Time.days_in_month(month, year)
298
+ last_hour(days_since(last_day - day))
299
+ end
300
+ alias :at_end_of_month :end_of_month
301
+
302
+ # Returns a new date/time representing the end of the year.
303
+ # DateTime objects will have a time set to 23:59:59.
304
+ def end_of_year
305
+ change(month: 12).end_of_month
306
+ end
307
+ alias :at_end_of_year :end_of_year
308
+
309
+ # Returns a Range representing the whole day of the current date/time.
310
+ def all_day
311
+ beginning_of_day..end_of_day
312
+ end
313
+
314
+ # Returns a Range representing the whole week of the current date/time.
315
+ # Week starts on start_day, default is <tt>Date.beginning_of_week</tt> or <tt>config.beginning_of_week</tt> when set.
316
+ def all_week(start_day = Date.beginning_of_week)
317
+ beginning_of_week(start_day)..end_of_week(start_day)
318
+ end
319
+
320
+ # Returns a Range representing the whole month of the current date/time.
321
+ def all_month
322
+ beginning_of_month..end_of_month
323
+ end
324
+
325
+ # Returns a Range representing the whole quarter of the current date/time.
326
+ def all_quarter
327
+ beginning_of_quarter..end_of_quarter
328
+ end
329
+
330
+ # Returns a Range representing the whole year of the current date/time.
331
+ def all_year
332
+ beginning_of_year..end_of_year
333
+ end
334
+
335
+ # Returns a new date/time representing the next occurrence of the specified day of week.
336
+ #
337
+ # today = Date.today # => Thu, 14 Dec 2017
338
+ # today.next_occurring(:monday) # => Mon, 18 Dec 2017
339
+ # today.next_occurring(:thursday) # => Thu, 21 Dec 2017
340
+ def next_occurring(day_of_week)
341
+ from_now = DAYS_INTO_WEEK.fetch(day_of_week) - wday
342
+ from_now += 7 unless from_now > 0
343
+ advance(days: from_now)
344
+ end
345
+
346
+ # Returns a new date/time representing the previous occurrence of the specified day of week.
347
+ #
348
+ # today = Date.today # => Thu, 14 Dec 2017
349
+ # today.prev_occurring(:monday) # => Mon, 11 Dec 2017
350
+ # today.prev_occurring(:thursday) # => Thu, 07 Dec 2017
351
+ def prev_occurring(day_of_week)
352
+ ago = wday - DAYS_INTO_WEEK.fetch(day_of_week)
353
+ ago += 7 unless ago > 0
354
+ advance(days: -ago)
355
+ end
356
+
357
+ private
358
+ def first_hour(date_or_time)
359
+ date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time
360
+ end
361
+
362
+ def last_hour(date_or_time)
363
+ date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time
364
+ end
365
+
366
+ def days_span(day)
367
+ (DAYS_INTO_WEEK.fetch(day) - DAYS_INTO_WEEK.fetch(Date.beginning_of_week)) % 7
368
+ end
369
+
370
+ def copy_time_to(other)
371
+ other.change(hour: hour, min: min, sec: sec, nsec: try(:nsec))
372
+ end
373
+ end
374
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors"
4
+ require "active_support/core_ext/module/redefine_method"
5
+
6
+ module DateAndTime
7
+ module Compatibility
8
+ # Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
9
+ #
10
+ # When +true+, it returns local times with a UTC offset, with +false+ local
11
+ # times are returned as UTC.
12
+ #
13
+ # # Given this zone:
14
+ # zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"]
15
+ #
16
+ # # With `utc_to_local_returns_utc_offset_times = false`, local time is converted to UTC:
17
+ # zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 UTC
18
+ #
19
+ # # With `utc_to_local_returns_utc_offset_times = true`, local time is returned with UTC offset:
20
+ # zone.utc_to_local(Time.utc(2000, 1)) # => 1999-12-31 19:00:00 -0500
21
+ mattr_accessor :utc_to_local_returns_utc_offset_times, instance_writer: false, default: false
22
+ end
23
+ end
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DateAndTime
4
+ module Zones
5
+ # Returns the simultaneous time in <tt>Time.zone</tt> if a zone is given or
6
+ # if Time.zone_default is set. Otherwise, it returns the current time.
7
+ #
8
+ # Time.zone = 'Hawaii' # => 'Hawaii'
9
+ # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
10
+ # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
11
+ #
12
+ # This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
13
+ # instead of the operating system's time zone.
14
+ #
15
+ # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
16
+ # and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
17
+ #
18
+ # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
19
+ # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
20
+ def in_time_zone(zone = ::Time.zone)
21
+ time_zone = ::Time.find_zone! zone
22
+ time = acts_like?(:time) ? self : nil
23
+
24
+ if time_zone
25
+ time_with_zone(time, time_zone)
26
+ else
27
+ time || to_time
28
+ end
29
+ end
30
+
31
+ private
32
+ def time_with_zone(time, zone)
33
+ if time
34
+ ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone)
35
+ else
36
+ ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc))
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/core_ext/object/acts_like"
5
+
6
+ class DateTime
7
+ # Duck-types as a Date-like class. See Object#acts_like?.
8
+ def acts_like_date?
9
+ true
10
+ end
11
+
12
+ # Duck-types as a Time-like class. See Object#acts_like?.
13
+ def acts_like_time?
14
+ true
15
+ end
16
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ class DateTime # :nodoc:
6
+ # No DateTime is ever blank:
7
+ #
8
+ # DateTime.now.blank? # => false
9
+ #
10
+ # @return [false]
11
+ def blank?
12
+ false
13
+ end
14
+
15
+ def present?
16
+ true
17
+ end
18
+ end
@@ -0,0 +1,215 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+
5
+ class DateTime
6
+ class << self
7
+ # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or
8
+ # <tt>config.time_zone</tt> are set, otherwise returns
9
+ # <tt>Time.now.to_datetime</tt>.
10
+ def current
11
+ ::Time.zone ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
12
+ end
13
+ end
14
+
15
+ # Returns the number of seconds since 00:00:00.
16
+ #
17
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
18
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
19
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
20
+ def seconds_since_midnight
21
+ sec + (min * 60) + (hour * 3600)
22
+ end
23
+
24
+ # Returns the number of seconds until 23:59:59.
25
+ #
26
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399
27
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103
28
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_until_end_of_day # => 0
29
+ def seconds_until_end_of_day
30
+ end_of_day.to_i - to_i
31
+ end
32
+
33
+ # Returns the fraction of a second as a +Rational+
34
+ #
35
+ # DateTime.new(2012, 8, 29, 0, 0, 0.5).subsec # => (1/2)
36
+ def subsec
37
+ sec_fraction
38
+ end
39
+
40
+ # Returns a new DateTime where one or more of the elements have been changed
41
+ # according to the +options+ parameter. The time options (<tt>:hour</tt>,
42
+ # <tt>:min</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is
43
+ # passed, then minute and sec is set to 0. If the hour and minute is passed,
44
+ # then sec is set to 0. The +options+ parameter takes a hash with any of these
45
+ # keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>,
46
+ # <tt>:min</tt>, <tt>:sec</tt>, <tt>:offset</tt>, <tt>:start</tt>.
47
+ #
48
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => DateTime.new(2012, 8, 1, 22, 35, 0)
49
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => DateTime.new(1981, 8, 1, 22, 35, 0)
50
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
51
+ def change(options)
52
+ if new_nsec = options[:nsec]
53
+ raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
54
+ new_fraction = Rational(new_nsec, 1000000000)
55
+ else
56
+ new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
57
+ new_fraction = Rational(new_usec, 1000000)
58
+ end
59
+
60
+ raise ArgumentError, "argument out of range" if new_fraction >= 1
61
+
62
+ ::DateTime.civil(
63
+ options.fetch(:year, year),
64
+ options.fetch(:month, month),
65
+ options.fetch(:day, day),
66
+ options.fetch(:hour, hour),
67
+ options.fetch(:min, options[:hour] ? 0 : min),
68
+ options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec) + new_fraction,
69
+ options.fetch(:offset, offset),
70
+ options.fetch(:start, start)
71
+ )
72
+ end
73
+
74
+ # Uses Date to provide precise Time calculations for years, months, and days.
75
+ # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
76
+ # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
77
+ # <tt>:minutes</tt>, <tt>:seconds</tt>.
78
+ #
79
+ # Just like Date#advance, increments are applied in order of time units from
80
+ # largest to smallest. This order can affect the result around the end of a
81
+ # month.
82
+ def advance(options)
83
+ unless options[:weeks].nil?
84
+ options[:weeks], partial_weeks = options[:weeks].divmod(1)
85
+ options[:days] = options.fetch(:days, 0) + 7 * partial_weeks
86
+ end
87
+
88
+ unless options[:days].nil?
89
+ options[:days], partial_days = options[:days].divmod(1)
90
+ options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
91
+ end
92
+
93
+ d = to_date.advance(options)
94
+ datetime_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
95
+ seconds_to_advance = \
96
+ options.fetch(:seconds, 0) +
97
+ options.fetch(:minutes, 0) * 60 +
98
+ options.fetch(:hours, 0) * 3600
99
+
100
+ if seconds_to_advance.zero?
101
+ datetime_advanced_by_date
102
+ else
103
+ datetime_advanced_by_date.since(seconds_to_advance)
104
+ end
105
+ end
106
+
107
+ # Returns a new DateTime representing the time a number of seconds ago.
108
+ # Do not use this method in combination with x.months, use months_ago instead!
109
+ def ago(seconds)
110
+ since(-seconds)
111
+ end
112
+
113
+ # Returns a new DateTime representing the time a number of seconds since the
114
+ # instance time. Do not use this method in combination with x.months, use
115
+ # months_since instead!
116
+ def since(seconds)
117
+ self + Rational(seconds, 86400)
118
+ end
119
+ alias :in :since
120
+
121
+ # Returns a new DateTime representing the start of the day (0:00).
122
+ def beginning_of_day
123
+ change(hour: 0)
124
+ end
125
+ alias :midnight :beginning_of_day
126
+ alias :at_midnight :beginning_of_day
127
+ alias :at_beginning_of_day :beginning_of_day
128
+
129
+ # Returns a new DateTime representing the middle of the day (12:00)
130
+ def middle_of_day
131
+ change(hour: 12)
132
+ end
133
+ alias :midday :middle_of_day
134
+ alias :noon :middle_of_day
135
+ alias :at_midday :middle_of_day
136
+ alias :at_noon :middle_of_day
137
+ alias :at_middle_of_day :middle_of_day
138
+
139
+ # Returns a new DateTime representing the end of the day (23:59:59).
140
+ def end_of_day
141
+ change(hour: 23, min: 59, sec: 59, usec: Rational(999999999, 1000))
142
+ end
143
+ alias :at_end_of_day :end_of_day
144
+
145
+ # Returns a new DateTime representing the start of the hour (hh:00:00).
146
+ def beginning_of_hour
147
+ change(min: 0)
148
+ end
149
+ alias :at_beginning_of_hour :beginning_of_hour
150
+
151
+ # Returns a new DateTime representing the end of the hour (hh:59:59).
152
+ def end_of_hour
153
+ change(min: 59, sec: 59, usec: Rational(999999999, 1000))
154
+ end
155
+ alias :at_end_of_hour :end_of_hour
156
+
157
+ # Returns a new DateTime representing the start of the minute (hh:mm:00).
158
+ def beginning_of_minute
159
+ change(sec: 0)
160
+ end
161
+ alias :at_beginning_of_minute :beginning_of_minute
162
+
163
+ # Returns a new DateTime representing the end of the minute (hh:mm:59).
164
+ def end_of_minute
165
+ change(sec: 59, usec: Rational(999999999, 1000))
166
+ end
167
+ alias :at_end_of_minute :end_of_minute
168
+
169
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
170
+ def localtime(utc_offset = nil)
171
+ utc = new_offset(0)
172
+
173
+ Time.utc(
174
+ utc.year, utc.month, utc.day,
175
+ utc.hour, utc.min, utc.sec + utc.sec_fraction
176
+ ).getlocal(utc_offset)
177
+ end
178
+ alias_method :getlocal, :localtime
179
+
180
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
181
+ #
182
+ # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
183
+ # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC
184
+ def utc
185
+ utc = new_offset(0)
186
+
187
+ Time.utc(
188
+ utc.year, utc.month, utc.day,
189
+ utc.hour, utc.min, utc.sec + utc.sec_fraction
190
+ )
191
+ end
192
+ alias_method :getgm, :utc
193
+ alias_method :getutc, :utc
194
+ alias_method :gmtime, :utc
195
+
196
+ # Returns +true+ if <tt>offset == 0</tt>.
197
+ def utc?
198
+ offset == 0
199
+ end
200
+
201
+ # Returns the offset value in seconds.
202
+ def utc_offset
203
+ (offset * 86400).to_i
204
+ end
205
+
206
+ # Layers additional behavior on DateTime#<=> so that Time and
207
+ # ActiveSupport::TimeWithZone instances can be compared with a DateTime.
208
+ def <=>(other)
209
+ if other.respond_to? :to_datetime
210
+ super other.to_datetime rescue nil
211
+ else
212
+ super
213
+ end
214
+ end
215
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/date_and_time/compatibility"
4
+ require "active_support/core_ext/module/redefine_method"
5
+
6
+ class DateTime
7
+ include DateAndTime::Compatibility
8
+
9
+ silence_redefinition_of_method :to_time
10
+
11
+ # Return an instance of +Time+ with the same UTC offset
12
+ # as +self+.
13
+ def to_time
14
+ getlocal(utc_offset)
15
+ end
16
+ end