activesupport 4.0.13 → 5.2.5

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 (264) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +412 -444
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +8 -4
  5. data/lib/active_support/all.rb +5 -3
  6. data/lib/active_support/array_inquirer.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +14 -12
  8. data/lib/active_support/benchmarkable.rb +6 -14
  9. data/lib/active_support/builder.rb +3 -1
  10. data/lib/active_support/cache/file_store.rb +67 -51
  11. data/lib/active_support/cache/mem_cache_store.rb +95 -97
  12. data/lib/active_support/cache/memory_store.rb +28 -30
  13. data/lib/active_support/cache/null_store.rb +7 -8
  14. data/lib/active_support/cache/redis_cache_store.rb +466 -0
  15. data/lib/active_support/cache/strategy/local_cache.rb +70 -56
  16. data/lib/active_support/cache/strategy/local_cache_middleware.rb +45 -0
  17. data/lib/active_support/cache.rb +331 -206
  18. data/lib/active_support/callbacks.rb +697 -426
  19. data/lib/active_support/concern.rb +32 -10
  20. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +17 -0
  21. data/lib/active_support/concurrency/share_lock.rb +227 -0
  22. data/lib/active_support/configurable.rb +8 -5
  23. data/lib/active_support/core_ext/array/access.rb +39 -1
  24. data/lib/active_support/core_ext/array/conversions.rb +24 -35
  25. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  26. data/lib/active_support/core_ext/array/grouping.rb +23 -13
  27. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  28. data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -5
  29. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  30. data/lib/active_support/core_ext/array.rb +9 -7
  31. data/lib/active_support/core_ext/benchmark.rb +3 -1
  32. data/lib/active_support/core_ext/big_decimal/conversions.rb +9 -26
  33. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  34. data/lib/active_support/core_ext/class/attribute.rb +41 -23
  35. data/lib/active_support/core_ext/class/attribute_accessors.rb +5 -169
  36. data/lib/active_support/core_ext/class/subclasses.rb +20 -8
  37. data/lib/active_support/core_ext/class.rb +4 -4
  38. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  39. data/lib/active_support/core_ext/date/blank.rb +14 -0
  40. data/lib/active_support/core_ext/date/calculations.rb +21 -9
  41. data/lib/active_support/core_ext/date/conversions.rb +32 -22
  42. data/lib/active_support/core_ext/date/zones.rb +5 -34
  43. data/lib/active_support/core_ext/date.rb +6 -4
  44. data/lib/active_support/core_ext/date_and_time/calculations.rb +199 -57
  45. data/lib/active_support/core_ext/date_and_time/compatibility.rb +16 -0
  46. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  47. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  48. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  49. data/lib/active_support/core_ext/date_time/calculations.rb +78 -37
  50. data/lib/active_support/core_ext/date_time/compatibility.rb +18 -0
  51. data/lib/active_support/core_ext/date_time/conversions.rb +19 -13
  52. data/lib/active_support/core_ext/date_time.rb +7 -4
  53. data/lib/active_support/core_ext/digest/uuid.rb +53 -0
  54. data/lib/active_support/core_ext/digest.rb +3 -0
  55. data/lib/active_support/core_ext/enumerable.rb +113 -29
  56. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  57. data/lib/active_support/core_ext/file.rb +3 -1
  58. data/lib/active_support/core_ext/hash/compact.rb +29 -0
  59. data/lib/active_support/core_ext/hash/conversions.rb +71 -49
  60. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  61. data/lib/active_support/core_ext/hash/except.rb +12 -3
  62. data/lib/active_support/core_ext/hash/indifferent_access.rb +5 -3
  63. data/lib/active_support/core_ext/hash/keys.rb +50 -38
  64. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  65. data/lib/active_support/core_ext/hash/slice.rb +12 -6
  66. data/lib/active_support/core_ext/hash/transform_values.rb +32 -0
  67. data/lib/active_support/core_ext/hash.rb +11 -8
  68. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  69. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  70. data/lib/active_support/core_ext/integer/time.rb +11 -33
  71. data/lib/active_support/core_ext/integer.rb +5 -3
  72. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +14 -0
  74. data/lib/active_support/core_ext/kernel/reporting.rb +5 -74
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +6 -4
  77. data/lib/active_support/core_ext/load_error.rb +5 -21
  78. data/lib/active_support/core_ext/marshal.rb +13 -10
  79. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  80. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  81. data/lib/active_support/core_ext/module/attr_internal.rb +8 -8
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +170 -21
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +150 -0
  84. data/lib/active_support/core_ext/module/concerning.rb +134 -0
  85. data/lib/active_support/core_ext/module/delegation.rb +135 -45
  86. data/lib/active_support/core_ext/module/deprecation.rb +3 -3
  87. data/lib/active_support/core_ext/module/introspection.rb +9 -25
  88. data/lib/active_support/core_ext/module/reachable.rb +5 -2
  89. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  90. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  91. data/lib/active_support/core_ext/module.rb +14 -10
  92. data/lib/active_support/core_ext/name_error.rb +22 -2
  93. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  94. data/lib/active_support/core_ext/numeric/conversions.rb +79 -74
  95. data/lib/active_support/core_ext/numeric/inquiry.rb +28 -0
  96. data/lib/active_support/core_ext/numeric/time.rb +37 -50
  97. data/lib/active_support/core_ext/numeric.rb +6 -3
  98. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  99. data/lib/active_support/core_ext/object/blank.rb +70 -19
  100. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  101. data/lib/active_support/core_ext/object/deep_dup.rb +19 -10
  102. data/lib/active_support/core_ext/object/duplicable.rb +100 -34
  103. data/lib/active_support/core_ext/object/inclusion.rb +18 -15
  104. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  105. data/lib/active_support/core_ext/object/json.rb +227 -0
  106. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  107. data/lib/active_support/core_ext/object/to_query.rb +21 -8
  108. data/lib/active_support/core_ext/object/try.rb +94 -24
  109. data/lib/active_support/core_ext/object/with_options.rb +45 -5
  110. data/lib/active_support/core_ext/object.rb +14 -12
  111. data/lib/active_support/core_ext/range/compare_range.rb +61 -0
  112. data/lib/active_support/core_ext/range/conversions.rb +27 -7
  113. data/lib/active_support/core_ext/range/each.rb +19 -17
  114. data/lib/active_support/core_ext/range/include_range.rb +2 -22
  115. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  116. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  117. data/lib/active_support/core_ext/range.rb +7 -4
  118. data/lib/active_support/core_ext/regexp.rb +6 -0
  119. data/lib/active_support/core_ext/securerandom.rb +25 -0
  120. data/lib/active_support/core_ext/string/access.rb +41 -39
  121. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  122. data/lib/active_support/core_ext/string/conversions.rb +17 -13
  123. data/lib/active_support/core_ext/string/exclude.rb +5 -3
  124. data/lib/active_support/core_ext/string/filters.rb +55 -6
  125. data/lib/active_support/core_ext/string/indent.rb +6 -4
  126. data/lib/active_support/core_ext/string/inflections.rb +66 -24
  127. data/lib/active_support/core_ext/string/inquiry.rb +3 -1
  128. data/lib/active_support/core_ext/string/multibyte.rb +15 -7
  129. data/lib/active_support/core_ext/string/output_safety.rb +114 -54
  130. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  131. data/lib/active_support/core_ext/string/strip.rb +4 -5
  132. data/lib/active_support/core_ext/string/zones.rb +4 -1
  133. data/lib/active_support/core_ext/string.rb +15 -13
  134. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  135. data/lib/active_support/core_ext/time/calculations.rb +123 -110
  136. data/lib/active_support/core_ext/time/compatibility.rb +16 -0
  137. data/lib/active_support/core_ext/time/conversions.rb +23 -14
  138. data/lib/active_support/core_ext/time/zones.rb +42 -26
  139. data/lib/active_support/core_ext/time.rb +7 -5
  140. data/lib/active_support/core_ext/uri.rb +6 -8
  141. data/lib/active_support/core_ext.rb +3 -2
  142. data/lib/active_support/current_attributes.rb +195 -0
  143. data/lib/active_support/dependencies/autoload.rb +3 -1
  144. data/lib/active_support/dependencies/interlock.rb +57 -0
  145. data/lib/active_support/dependencies.rb +196 -166
  146. data/lib/active_support/deprecation/behaviors.rb +48 -15
  147. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +17 -2
  149. data/lib/active_support/deprecation/method_wrappers.rb +66 -20
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +56 -28
  151. data/lib/active_support/deprecation/reporting.rb +32 -12
  152. data/lib/active_support/deprecation.rb +14 -11
  153. data/lib/active_support/descendants_tracker.rb +2 -0
  154. data/lib/active_support/digest.rb +20 -0
  155. data/lib/active_support/duration/iso8601_parser.rb +125 -0
  156. data/lib/active_support/duration/iso8601_serializer.rb +55 -0
  157. data/lib/active_support/duration.rb +354 -34
  158. data/lib/active_support/encrypted_configuration.rb +49 -0
  159. data/lib/active_support/encrypted_file.rb +99 -0
  160. data/lib/active_support/evented_file_update_checker.rb +205 -0
  161. data/lib/active_support/execution_wrapper.rb +128 -0
  162. data/lib/active_support/executor.rb +8 -0
  163. data/lib/active_support/file_update_checker.rb +63 -37
  164. data/lib/active_support/gem_version.rb +17 -0
  165. data/lib/active_support/gzip.rb +7 -5
  166. data/lib/active_support/hash_with_indifferent_access.rb +158 -35
  167. data/lib/active_support/i18n.rb +8 -6
  168. data/lib/active_support/i18n_railtie.rb +38 -20
  169. data/lib/active_support/inflections.rb +19 -12
  170. data/lib/active_support/inflector/inflections.rb +79 -30
  171. data/lib/active_support/inflector/methods.rb +197 -129
  172. data/lib/active_support/inflector/transliterate.rb +48 -27
  173. data/lib/active_support/inflector.rb +7 -5
  174. data/lib/active_support/json/decoding.rb +21 -25
  175. data/lib/active_support/json/encoding.rb +84 -292
  176. data/lib/active_support/json.rb +4 -2
  177. data/lib/active_support/key_generator.rb +26 -28
  178. data/lib/active_support/lazy_load_hooks.rb +51 -21
  179. data/lib/active_support/locale/en.yml +2 -0
  180. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  181. data/lib/active_support/log_subscriber.rb +13 -10
  182. data/lib/active_support/logger.rb +54 -3
  183. data/lib/active_support/logger_silence.rb +12 -7
  184. data/lib/active_support/logger_thread_safe_level.rb +34 -0
  185. data/lib/active_support/message_encryptor.rb +173 -50
  186. data/lib/active_support/message_verifier.rb +159 -22
  187. data/lib/active_support/messages/metadata.rb +71 -0
  188. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  189. data/lib/active_support/messages/rotator.rb +56 -0
  190. data/lib/active_support/multibyte/chars.rb +38 -26
  191. data/lib/active_support/multibyte/unicode.rb +138 -146
  192. data/lib/active_support/multibyte.rb +4 -2
  193. data/lib/active_support/notifications/fanout.rb +23 -16
  194. data/lib/active_support/notifications/instrumenter.rb +29 -8
  195. data/lib/active_support/notifications.rb +22 -13
  196. data/lib/active_support/number_helper/number_converter.rb +184 -0
  197. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  198. data/lib/active_support/number_helper/number_to_delimited_converter.rb +29 -0
  199. data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
  200. data/lib/active_support/number_helper/number_to_human_size_converter.rb +59 -0
  201. data/lib/active_support/number_helper/number_to_percentage_converter.rb +14 -0
  202. data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
  203. data/lib/active_support/number_helper/number_to_rounded_converter.rb +54 -0
  204. data/lib/active_support/number_helper/rounding_helper.rb +66 -0
  205. data/lib/active_support/number_helper.rb +125 -391
  206. data/lib/active_support/option_merger.rb +3 -1
  207. data/lib/active_support/ordered_hash.rb +6 -4
  208. data/lib/active_support/ordered_options.rb +31 -5
  209. data/lib/active_support/per_thread_registry.rb +19 -11
  210. data/lib/active_support/proxy_object.rb +2 -0
  211. data/lib/active_support/rails.rb +16 -8
  212. data/lib/active_support/railtie.rb +43 -9
  213. data/lib/active_support/reloader.rb +131 -0
  214. data/lib/active_support/rescuable.rb +108 -53
  215. data/lib/active_support/security_utils.rb +31 -0
  216. data/lib/active_support/string_inquirer.rb +11 -3
  217. data/lib/active_support/subscriber.rb +54 -17
  218. data/lib/active_support/tagged_logging.rb +14 -11
  219. data/lib/active_support/test_case.rb +42 -37
  220. data/lib/active_support/testing/assertions.rb +126 -39
  221. data/lib/active_support/testing/autorun.rb +5 -3
  222. data/lib/active_support/testing/constant_lookup.rb +3 -6
  223. data/lib/active_support/testing/declarative.rb +10 -22
  224. data/lib/active_support/testing/deprecation.rb +14 -10
  225. data/lib/active_support/testing/file_fixtures.rb +36 -0
  226. data/lib/active_support/testing/isolation.rb +55 -86
  227. data/lib/active_support/testing/method_call_assertions.rb +43 -0
  228. data/lib/active_support/testing/setup_and_teardown.rb +30 -10
  229. data/lib/active_support/testing/stream.rb +44 -0
  230. data/lib/active_support/testing/tagged_logging.rb +5 -3
  231. data/lib/active_support/testing/time_helpers.rb +200 -0
  232. data/lib/active_support/time.rb +13 -13
  233. data/lib/active_support/time_with_zone.rb +223 -73
  234. data/lib/active_support/values/time_zone.rb +261 -126
  235. data/lib/active_support/values/unicode_tables.dat +0 -0
  236. data/lib/active_support/version.rb +6 -7
  237. data/lib/active_support/xml_mini/jdom.rb +116 -113
  238. data/lib/active_support/xml_mini/libxml.rb +17 -16
  239. data/lib/active_support/xml_mini/libxmlsax.rb +16 -18
  240. data/lib/active_support/xml_mini/nokogiri.rb +15 -15
  241. data/lib/active_support/xml_mini/nokogirisax.rb +15 -16
  242. data/lib/active_support/xml_mini/rexml.rb +17 -16
  243. data/lib/active_support/xml_mini.rb +69 -51
  244. data/lib/active_support.rb +29 -3
  245. metadata +84 -54
  246. data/lib/active_support/basic_object.rb +0 -11
  247. data/lib/active_support/buffered_logger.rb +0 -21
  248. data/lib/active_support/concurrency/latch.rb +0 -27
  249. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  250. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -40
  251. data/lib/active_support/core_ext/date_time/zones.rb +0 -24
  252. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  253. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  254. data/lib/active_support/core_ext/logger.rb +0 -67
  255. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  256. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  257. data/lib/active_support/core_ext/proc.rb +0 -17
  258. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  259. data/lib/active_support/core_ext/struct.rb +0 -6
  260. data/lib/active_support/core_ext/thread.rb +0 -79
  261. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  262. data/lib/active_support/file_watcher.rb +0 -36
  263. data/lib/active_support/json/variable.rb +0 -18
  264. data/lib/active_support/testing/pending.rb +0 -14
@@ -1,23 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/object/try"
4
+
1
5
  module DateAndTime
2
6
  module Calculations
3
7
  DAYS_INTO_WEEK = {
4
- :monday => 0,
5
- :tuesday => 1,
6
- :wednesday => 2,
7
- :thursday => 3,
8
- :friday => 4,
9
- :saturday => 5,
10
- :sunday => 6
8
+ monday: 0,
9
+ tuesday: 1,
10
+ wednesday: 2,
11
+ thursday: 3,
12
+ friday: 4,
13
+ saturday: 5,
14
+ sunday: 6
11
15
  }
16
+ WEEKEND_DAYS = [ 6, 0 ]
12
17
 
13
18
  # Returns a new date/time representing yesterday.
14
19
  def yesterday
15
- advance(:days => -1)
20
+ advance(days: -1)
21
+ end
22
+
23
+ # Returns a new date/time the specified number of days ago.
24
+ def prev_day(days = 1)
25
+ advance(days: -days)
16
26
  end
17
27
 
18
28
  # Returns a new date/time representing tomorrow.
19
29
  def tomorrow
20
- advance(:days => 1)
30
+ advance(days: 1)
31
+ end
32
+
33
+ # Returns a new date/time the specified number of days in the future.
34
+ def next_day(days = 1)
35
+ advance(days: days)
21
36
  end
22
37
 
23
38
  # Returns true if the date/time is today.
@@ -35,90 +50,147 @@ module DateAndTime
35
50
  self > self.class.current
36
51
  end
37
52
 
53
+ # Returns true if the date/time falls on a Saturday or Sunday.
54
+ def on_weekend?
55
+ WEEKEND_DAYS.include?(wday)
56
+ end
57
+
58
+ # Returns true if the date/time does not fall on a Saturday or Sunday.
59
+ def on_weekday?
60
+ !WEEKEND_DAYS.include?(wday)
61
+ end
62
+
38
63
  # Returns a new date/time the specified number of days ago.
39
64
  def days_ago(days)
40
- advance(:days => -days)
65
+ advance(days: -days)
41
66
  end
42
67
 
43
68
  # Returns a new date/time the specified number of days in the future.
44
69
  def days_since(days)
45
- advance(:days => days)
70
+ advance(days: days)
46
71
  end
47
72
 
48
73
  # Returns a new date/time the specified number of weeks ago.
49
74
  def weeks_ago(weeks)
50
- advance(:weeks => -weeks)
75
+ advance(weeks: -weeks)
51
76
  end
52
77
 
53
78
  # Returns a new date/time the specified number of weeks in the future.
54
79
  def weeks_since(weeks)
55
- advance(:weeks => weeks)
80
+ advance(weeks: weeks)
56
81
  end
57
82
 
58
83
  # Returns a new date/time the specified number of months ago.
59
84
  def months_ago(months)
60
- advance(:months => -months)
85
+ advance(months: -months)
61
86
  end
62
87
 
63
88
  # Returns a new date/time the specified number of months in the future.
64
89
  def months_since(months)
65
- advance(:months => months)
90
+ advance(months: months)
66
91
  end
67
92
 
68
93
  # Returns a new date/time the specified number of years ago.
69
94
  def years_ago(years)
70
- advance(:years => -years)
95
+ advance(years: -years)
71
96
  end
72
97
 
73
98
  # Returns a new date/time the specified number of years in the future.
74
99
  def years_since(years)
75
- advance(:years => years)
100
+ advance(years: years)
76
101
  end
77
102
 
78
103
  # Returns a new date/time at the start of the month.
79
- # DateTime objects will have a time set to 0:00.
104
+ #
105
+ # today = Date.today # => Thu, 18 Jun 2015
106
+ # today.beginning_of_month # => Mon, 01 Jun 2015
107
+ #
108
+ # +DateTime+ objects will have a time set to 0:00.
109
+ #
110
+ # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000
111
+ # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000
80
112
  def beginning_of_month
81
- first_hour{ change(:day => 1) }
113
+ first_hour(change(day: 1))
82
114
  end
83
115
  alias :at_beginning_of_month :beginning_of_month
84
116
 
85
117
  # Returns a new date/time at the start of the quarter.
86
- # Example: 1st January, 1st July, 1st October.
87
- # DateTime objects will have a time set to 0:00.
118
+ #
119
+ # today = Date.today # => Fri, 10 Jul 2015
120
+ # today.beginning_of_quarter # => Wed, 01 Jul 2015
121
+ #
122
+ # +DateTime+ objects will have a time set to 0:00.
123
+ #
124
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
125
+ # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
88
126
  def beginning_of_quarter
89
127
  first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
90
- beginning_of_month.change(:month => first_quarter_month)
128
+ beginning_of_month.change(month: first_quarter_month)
91
129
  end
92
130
  alias :at_beginning_of_quarter :beginning_of_quarter
93
131
 
94
132
  # Returns a new date/time at the end of the quarter.
95
- # Example: 31st March, 30th June, 30th September.
96
- # DateTime objects will have a time set to 23:59:59.
133
+ #
134
+ # today = Date.today # => Fri, 10 Jul 2015
135
+ # today.end_of_quarter # => Wed, 30 Sep 2015
136
+ #
137
+ # +DateTime+ objects will have a time set to 23:59:59.
138
+ #
139
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
140
+ # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
97
141
  def end_of_quarter
98
142
  last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
99
- beginning_of_month.change(:month => last_quarter_month).end_of_month
143
+ beginning_of_month.change(month: last_quarter_month).end_of_month
100
144
  end
101
145
  alias :at_end_of_quarter :end_of_quarter
102
146
 
103
- # Return a new date/time at the beginning of the year.
104
- # Example: 1st January.
105
- # DateTime objects will have a time set to 0:00.
147
+ # Returns a new date/time at the beginning of the year.
148
+ #
149
+ # today = Date.today # => Fri, 10 Jul 2015
150
+ # today.beginning_of_year # => Thu, 01 Jan 2015
151
+ #
152
+ # +DateTime+ objects will have a time set to 0:00.
153
+ #
154
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
155
+ # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000
106
156
  def beginning_of_year
107
- change(:month => 1).beginning_of_month
157
+ change(month: 1).beginning_of_month
108
158
  end
109
159
  alias :at_beginning_of_year :beginning_of_year
110
160
 
111
161
  # Returns a new date/time representing the given day in the next week.
162
+ #
163
+ # today = Date.today # => Thu, 07 May 2015
164
+ # today.next_week # => Mon, 11 May 2015
165
+ #
112
166
  # The +given_day_in_next_week+ defaults to the beginning of the week
113
167
  # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
114
- # when set. +DateTime+ objects have their time set to 0:00.
115
- def next_week(given_day_in_next_week = Date.beginning_of_week)
116
- first_hour{ weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)) }
168
+ # when set.
169
+ #
170
+ # today = Date.today # => Thu, 07 May 2015
171
+ # today.next_week(:friday) # => Fri, 15 May 2015
172
+ #
173
+ # +DateTime+ objects have their time set to 0:00 unless +same_time+ is true.
174
+ #
175
+ # now = DateTime.current # => Thu, 07 May 2015 13:31:16 +0000
176
+ # now.next_week # => Mon, 11 May 2015 00:00:00 +0000
177
+ def next_week(given_day_in_next_week = Date.beginning_of_week, same_time: false)
178
+ result = first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
179
+ same_time ? copy_time_to(result) : result
180
+ end
181
+
182
+ # Returns a new date/time representing the next weekday.
183
+ def next_weekday
184
+ if next_day.on_weekend?
185
+ next_week(:monday, same_time: true)
186
+ else
187
+ next_day
188
+ end
117
189
  end
118
190
 
119
- # Short-hand for months_since(1).
120
- def next_month
121
- months_since(1)
191
+ # Returns a new date/time the specified number of months in the future.
192
+ def next_month(months = 1)
193
+ advance(months: months)
122
194
  end
123
195
 
124
196
  # Short-hand for months_since(3)
@@ -126,25 +198,40 @@ module DateAndTime
126
198
  months_since(3)
127
199
  end
128
200
 
129
- # Short-hand for years_since(1).
130
- def next_year
131
- years_since(1)
201
+ # Returns a new date/time the specified number of years in the future.
202
+ def next_year(years = 1)
203
+ advance(years: years)
132
204
  end
133
205
 
134
206
  # Returns a new date/time representing the given day in the previous week.
135
207
  # Week is assumed to start on +start_day+, default is
136
208
  # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
137
- # DateTime objects have their time set to 0:00.
138
- def prev_week(start_day = Date.beginning_of_week)
139
- first_hour{ weeks_ago(1).beginning_of_week.days_since(days_span(start_day)) }
209
+ # DateTime objects have their time set to 0:00 unless +same_time+ is true.
210
+ def prev_week(start_day = Date.beginning_of_week, same_time: false)
211
+ result = first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
212
+ same_time ? copy_time_to(result) : result
140
213
  end
141
214
  alias_method :last_week, :prev_week
142
215
 
216
+ # Returns a new date/time representing the previous weekday.
217
+ def prev_weekday
218
+ if prev_day.on_weekend?
219
+ copy_time_to(beginning_of_week(:friday))
220
+ else
221
+ prev_day
222
+ end
223
+ end
224
+ alias_method :last_weekday, :prev_weekday
225
+
226
+ # Returns a new date/time the specified number of months ago.
227
+ def prev_month(months = 1)
228
+ advance(months: -months)
229
+ end
230
+
143
231
  # Short-hand for months_ago(1).
144
- def prev_month
232
+ def last_month
145
233
  months_ago(1)
146
234
  end
147
- alias_method :last_month, :prev_month
148
235
 
149
236
  # Short-hand for months_ago(3).
150
237
  def prev_quarter
@@ -152,11 +239,15 @@ module DateAndTime
152
239
  end
153
240
  alias_method :last_quarter, :prev_quarter
154
241
 
242
+ # Returns a new date/time the specified number of years ago.
243
+ def prev_year(years = 1)
244
+ advance(years: -years)
245
+ end
246
+
155
247
  # Short-hand for years_ago(1).
156
- def prev_year
248
+ def last_year
157
249
  years_ago(1)
158
250
  end
159
- alias_method :last_year, :prev_year
160
251
 
161
252
  # Returns the number of days to the start of the week on the given day.
162
253
  # Week is assumed to start on +start_day+, default is
@@ -188,7 +279,7 @@ module DateAndTime
188
279
  # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
189
280
  # DateTime objects have their time set to 23:59:59.
190
281
  def end_of_week(start_day = Date.beginning_of_week)
191
- last_hour{ days_since(6 - days_to_week_start(start_day)) }
282
+ last_hour(days_since(6 - days_to_week_start(start_day)))
192
283
  end
193
284
  alias :at_end_of_week :end_of_week
194
285
 
@@ -202,31 +293,82 @@ module DateAndTime
202
293
  # DateTime objects will have a time set to 23:59:59.
203
294
  def end_of_month
204
295
  last_day = ::Time.days_in_month(month, year)
205
- last_hour{ days_since(last_day - day) }
296
+ last_hour(days_since(last_day - day))
206
297
  end
207
298
  alias :at_end_of_month :end_of_month
208
299
 
209
300
  # Returns a new date/time representing the end of the year.
210
301
  # DateTime objects will have a time set to 23:59:59.
211
302
  def end_of_year
212
- change(:month => 12).end_of_month
303
+ change(month: 12).end_of_month
213
304
  end
214
305
  alias :at_end_of_year :end_of_year
215
306
 
216
- private
307
+ # Returns a Range representing the whole day of the current date/time.
308
+ def all_day
309
+ beginning_of_day..end_of_day
310
+ end
311
+
312
+ # Returns a Range representing the whole week of the current date/time.
313
+ # Week starts on start_day, default is <tt>Date.beginning_of_week</tt> or <tt>config.beginning_of_week</tt> when set.
314
+ def all_week(start_day = Date.beginning_of_week)
315
+ beginning_of_week(start_day)..end_of_week(start_day)
316
+ end
217
317
 
218
- def first_hour
219
- result = yield
220
- acts_like?(:time) ? result.change(:hour => 0) : result
318
+ # Returns a Range representing the whole month of the current date/time.
319
+ def all_month
320
+ beginning_of_month..end_of_month
221
321
  end
222
322
 
223
- def last_hour
224
- result = yield
225
- acts_like?(:time) ? result.end_of_day : result
323
+ # Returns a Range representing the whole quarter of the current date/time.
324
+ def all_quarter
325
+ beginning_of_quarter..end_of_quarter
226
326
  end
227
327
 
228
- def days_span(day)
229
- (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
328
+ # Returns a Range representing the whole year of the current date/time.
329
+ def all_year
330
+ beginning_of_year..end_of_year
230
331
  end
332
+
333
+ # Returns a new date/time representing the next occurrence of the specified day of week.
334
+ #
335
+ # today = Date.today # => Thu, 14 Dec 2017
336
+ # today.next_occurring(:monday) # => Mon, 18 Dec 2017
337
+ # today.next_occurring(:thursday) # => Thu, 21 Dec 2017
338
+ def next_occurring(day_of_week)
339
+ current_day_number = wday != 0 ? wday - 1 : 6
340
+ from_now = DAYS_INTO_WEEK.fetch(day_of_week) - current_day_number
341
+ from_now += 7 unless from_now > 0
342
+ advance(days: from_now)
343
+ end
344
+
345
+ # Returns a new date/time representing the previous occurrence of the specified day of week.
346
+ #
347
+ # today = Date.today # => Thu, 14 Dec 2017
348
+ # today.prev_occurring(:monday) # => Mon, 11 Dec 2017
349
+ # today.prev_occurring(:thursday) # => Thu, 07 Dec 2017
350
+ def prev_occurring(day_of_week)
351
+ current_day_number = wday != 0 ? wday - 1 : 6
352
+ ago = current_day_number - 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[day] - DAYS_INTO_WEEK[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
231
373
  end
232
374
  end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/module/attribute_accessors"
4
+
5
+ module DateAndTime
6
+ module Compatibility
7
+ # If true, +to_time+ preserves the timezone offset of receiver.
8
+ #
9
+ # NOTE: With Ruby 2.4+ the default for +to_time+ changed from
10
+ # converting to the local system time, to preserving the offset
11
+ # of the receiver. For backwards compatibility we're overriding
12
+ # this behavior, but new apps will have an initializer that sets
13
+ # this to true, because the new behavior is preferred.
14
+ mattr_accessor :preserve_timezone, instance_writer: false, default: false
15
+ end
16
+ end
@@ -0,0 +1,41 @@
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
+
33
+ def time_with_zone(time, zone)
34
+ if time
35
+ ActiveSupport::TimeWithZone.new(time.utc? ? time : time.getutc, zone)
36
+ else
37
+ ActiveSupport::TimeWithZone.new(nil, zone, to_time(:utc))
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,5 +1,7 @@
1
- require 'date'
2
- require 'active_support/core_ext/object/acts_like'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/core_ext/object/acts_like"
3
5
 
4
6
  class DateTime
5
7
  # Duck-types as a Date-like class. See Object#acts_like?.
@@ -0,0 +1,14 @@
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
+ end
@@ -1,14 +1,9 @@
1
- require 'active_support/deprecation'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
2
4
 
3
5
  class DateTime
4
6
  class << self
5
- # *DEPRECATED*: Use +DateTime.civil_from_format+ directly.
6
- def local_offset
7
- ActiveSupport::Deprecation.warn 'DateTime.local_offset is deprecated. Use DateTime.civil_from_format directly.'
8
-
9
- ::Time.local(2012).utc_offset.to_r / 86400
10
- end
11
-
12
7
  # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or
13
8
  # <tt>config.time_zone</tt> are set, otherwise returns
14
9
  # <tt>Time.now.to_datetime</tt>.
@@ -17,17 +12,11 @@ class DateTime
17
12
  end
18
13
  end
19
14
 
20
- # Tells whether the DateTime object's datetime lies in the past.
21
- def past?
22
- self < ::DateTime.current
23
- end
24
-
25
- # Tells whether the DateTime object's datetime lies in the future.
26
- def future?
27
- self > ::DateTime.current
28
- end
29
-
30
- # Seconds since midnight: DateTime.now.seconds_since_midnight.
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
31
20
  def seconds_since_midnight
32
21
  sec + (min * 60) + (hour * 3600)
33
22
  end
@@ -41,6 +30,13 @@ class DateTime
41
30
  end_of_day.to_i - to_i
42
31
  end
43
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
+
44
40
  # Returns a new DateTime where one or more of the elements have been changed
45
41
  # according to the +options+ parameter. The time options (<tt>:hour</tt>,
46
42
  # <tt>:min</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is
@@ -53,13 +49,23 @@ class DateTime
53
49
  # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => DateTime.new(1981, 8, 1, 22, 35, 0)
54
50
  # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
55
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
+
56
62
  ::DateTime.civil(
57
63
  options.fetch(:year, year),
58
64
  options.fetch(:month, month),
59
65
  options.fetch(:day, day),
60
66
  options.fetch(:hour, hour),
61
67
  options.fetch(:min, options[:hour] ? 0 : min),
62
- options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec + sec_fraction),
68
+ options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec) + new_fraction,
63
69
  options.fetch(:offset, offset),
64
70
  options.fetch(:start, start)
65
71
  )
@@ -70,8 +76,18 @@ class DateTime
70
76
  # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
71
77
  # <tt>:minutes</tt>, <tt>:seconds</tt>.
72
78
  def advance(options)
79
+ unless options[:weeks].nil?
80
+ options[:weeks], partial_weeks = options[:weeks].divmod(1)
81
+ options[:days] = options.fetch(:days, 0) + 7 * partial_weeks
82
+ end
83
+
84
+ unless options[:days].nil?
85
+ options[:days], partial_days = options[:days].divmod(1)
86
+ options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
87
+ end
88
+
73
89
  d = to_date.advance(options)
74
- datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
90
+ datetime_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
75
91
  seconds_to_advance = \
76
92
  options.fetch(:seconds, 0) +
77
93
  options.fetch(:minutes, 0) * 60 +
@@ -80,7 +96,7 @@ class DateTime
80
96
  if seconds_to_advance.zero?
81
97
  datetime_advanced_by_date
82
98
  else
83
- datetime_advanced_by_date.since seconds_to_advance
99
+ datetime_advanced_by_date.since(seconds_to_advance)
84
100
  end
85
101
  end
86
102
 
@@ -100,50 +116,78 @@ class DateTime
100
116
 
101
117
  # Returns a new DateTime representing the start of the day (0:00).
102
118
  def beginning_of_day
103
- change(:hour => 0)
119
+ change(hour: 0)
104
120
  end
105
121
  alias :midnight :beginning_of_day
106
122
  alias :at_midnight :beginning_of_day
107
123
  alias :at_beginning_of_day :beginning_of_day
108
124
 
125
+ # Returns a new DateTime representing the middle of the day (12:00)
126
+ def middle_of_day
127
+ change(hour: 12)
128
+ end
129
+ alias :midday :middle_of_day
130
+ alias :noon :middle_of_day
131
+ alias :at_midday :middle_of_day
132
+ alias :at_noon :middle_of_day
133
+ alias :at_middle_of_day :middle_of_day
134
+
109
135
  # Returns a new DateTime representing the end of the day (23:59:59).
110
136
  def end_of_day
111
- change(:hour => 23, :min => 59, :sec => 59)
137
+ change(hour: 23, min: 59, sec: 59, usec: Rational(999999999, 1000))
112
138
  end
113
139
  alias :at_end_of_day :end_of_day
114
140
 
115
141
  # Returns a new DateTime representing the start of the hour (hh:00:00).
116
142
  def beginning_of_hour
117
- change(:min => 0)
143
+ change(min: 0)
118
144
  end
119
145
  alias :at_beginning_of_hour :beginning_of_hour
120
146
 
121
147
  # Returns a new DateTime representing the end of the hour (hh:59:59).
122
148
  def end_of_hour
123
- change(:min => 59, :sec => 59)
149
+ change(min: 59, sec: 59, usec: Rational(999999999, 1000))
124
150
  end
125
151
  alias :at_end_of_hour :end_of_hour
126
152
 
127
153
  # Returns a new DateTime representing the start of the minute (hh:mm:00).
128
154
  def beginning_of_minute
129
- change(:sec => 0)
155
+ change(sec: 0)
130
156
  end
131
157
  alias :at_beginning_of_minute :beginning_of_minute
132
158
 
133
159
  # Returns a new DateTime representing the end of the minute (hh:mm:59).
134
160
  def end_of_minute
135
- change(:sec => 59)
161
+ change(sec: 59, usec: Rational(999999999, 1000))
136
162
  end
137
163
  alias :at_end_of_minute :end_of_minute
138
164
 
139
- # Adjusts DateTime to UTC by adding its offset value; offset is set to 0.
165
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the system timezone.
166
+ def localtime(utc_offset = nil)
167
+ utc = new_offset(0)
168
+
169
+ Time.utc(
170
+ utc.year, utc.month, utc.day,
171
+ utc.hour, utc.min, utc.sec + utc.sec_fraction
172
+ ).getlocal(utc_offset)
173
+ end
174
+ alias_method :getlocal, :localtime
175
+
176
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
140
177
  #
141
178
  # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
142
- # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
179
+ # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC
143
180
  def utc
144
- new_offset(0)
181
+ utc = new_offset(0)
182
+
183
+ Time.utc(
184
+ utc.year, utc.month, utc.day,
185
+ utc.hour, utc.min, utc.sec + utc.sec_fraction
186
+ )
145
187
  end
188
+ alias_method :getgm, :utc
146
189
  alias_method :getutc, :utc
190
+ alias_method :gmtime, :utc
147
191
 
148
192
  # Returns +true+ if <tt>offset == 0</tt>.
149
193
  def utc?
@@ -158,13 +202,10 @@ class DateTime
158
202
  # Layers additional behavior on DateTime#<=> so that Time and
159
203
  # ActiveSupport::TimeWithZone instances can be compared with a DateTime.
160
204
  def <=>(other)
161
- if other.kind_of?(Infinity)
162
- super
163
- elsif other.respond_to? :to_datetime
164
- super other.to_datetime
205
+ if other.respond_to? :to_datetime
206
+ super other.to_datetime rescue nil
165
207
  else
166
- nil
208
+ super
167
209
  end
168
210
  end
169
-
170
211
  end