core_ext 0.0.1

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 (175) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +3 -0
  3. data/lib/core_ext/array/access.rb +76 -0
  4. data/lib/core_ext/array/conversions.rb +211 -0
  5. data/lib/core_ext/array/extract_options.rb +29 -0
  6. data/lib/core_ext/array/grouping.rb +116 -0
  7. data/lib/core_ext/array/inquiry.rb +17 -0
  8. data/lib/core_ext/array/prepend_and_append.rb +7 -0
  9. data/lib/core_ext/array/wrap.rb +46 -0
  10. data/lib/core_ext/array.rb +7 -0
  11. data/lib/core_ext/array_inquirer.rb +44 -0
  12. data/lib/core_ext/benchmark.rb +14 -0
  13. data/lib/core_ext/benchmarkable.rb +49 -0
  14. data/lib/core_ext/big_decimal/conversions.rb +14 -0
  15. data/lib/core_ext/big_decimal.rb +1 -0
  16. data/lib/core_ext/builder.rb +6 -0
  17. data/lib/core_ext/callbacks.rb +770 -0
  18. data/lib/core_ext/class/attribute.rb +128 -0
  19. data/lib/core_ext/class/attribute_accessors.rb +4 -0
  20. data/lib/core_ext/class/subclasses.rb +42 -0
  21. data/lib/core_ext/class.rb +2 -0
  22. data/lib/core_ext/concern.rb +142 -0
  23. data/lib/core_ext/configurable.rb +148 -0
  24. data/lib/core_ext/date/acts_like.rb +8 -0
  25. data/lib/core_ext/date/blank.rb +12 -0
  26. data/lib/core_ext/date/calculations.rb +143 -0
  27. data/lib/core_ext/date/conversions.rb +93 -0
  28. data/lib/core_ext/date/zones.rb +6 -0
  29. data/lib/core_ext/date.rb +5 -0
  30. data/lib/core_ext/date_and_time/calculations.rb +328 -0
  31. data/lib/core_ext/date_and_time/zones.rb +40 -0
  32. data/lib/core_ext/date_time/acts_like.rb +14 -0
  33. data/lib/core_ext/date_time/blank.rb +12 -0
  34. data/lib/core_ext/date_time/calculations.rb +177 -0
  35. data/lib/core_ext/date_time/conversions.rb +104 -0
  36. data/lib/core_ext/date_time/zones.rb +6 -0
  37. data/lib/core_ext/date_time.rb +5 -0
  38. data/lib/core_ext/deprecation/behaviors.rb +86 -0
  39. data/lib/core_ext/deprecation/instance_delegator.rb +24 -0
  40. data/lib/core_ext/deprecation/method_wrappers.rb +70 -0
  41. data/lib/core_ext/deprecation/proxy_wrappers.rb +149 -0
  42. data/lib/core_ext/deprecation/reporting.rb +105 -0
  43. data/lib/core_ext/deprecation.rb +43 -0
  44. data/lib/core_ext/digest/uuid.rb +51 -0
  45. data/lib/core_ext/duration.rb +157 -0
  46. data/lib/core_ext/enumerable.rb +106 -0
  47. data/lib/core_ext/file/atomic.rb +68 -0
  48. data/lib/core_ext/file.rb +1 -0
  49. data/lib/core_ext/hash/compact.rb +20 -0
  50. data/lib/core_ext/hash/conversions.rb +261 -0
  51. data/lib/core_ext/hash/deep_merge.rb +38 -0
  52. data/lib/core_ext/hash/except.rb +22 -0
  53. data/lib/core_ext/hash/indifferent_access.rb +23 -0
  54. data/lib/core_ext/hash/keys.rb +170 -0
  55. data/lib/core_ext/hash/reverse_merge.rb +22 -0
  56. data/lib/core_ext/hash/slice.rb +48 -0
  57. data/lib/core_ext/hash/transform_values.rb +29 -0
  58. data/lib/core_ext/hash.rb +9 -0
  59. data/lib/core_ext/hash_with_indifferent_access.rb +298 -0
  60. data/lib/core_ext/inflections.rb +70 -0
  61. data/lib/core_ext/inflector/inflections.rb +244 -0
  62. data/lib/core_ext/inflector/methods.rb +381 -0
  63. data/lib/core_ext/inflector/transliterate.rb +112 -0
  64. data/lib/core_ext/inflector.rb +7 -0
  65. data/lib/core_ext/integer/inflections.rb +29 -0
  66. data/lib/core_ext/integer/multiple.rb +10 -0
  67. data/lib/core_ext/integer/time.rb +29 -0
  68. data/lib/core_ext/integer.rb +3 -0
  69. data/lib/core_ext/json/decoding.rb +67 -0
  70. data/lib/core_ext/json/encoding.rb +127 -0
  71. data/lib/core_ext/json.rb +2 -0
  72. data/lib/core_ext/kernel/agnostics.rb +11 -0
  73. data/lib/core_ext/kernel/concern.rb +10 -0
  74. data/lib/core_ext/kernel/reporting.rb +41 -0
  75. data/lib/core_ext/kernel/singleton_class.rb +6 -0
  76. data/lib/core_ext/kernel.rb +4 -0
  77. data/lib/core_ext/load_error.rb +30 -0
  78. data/lib/core_ext/logger.rb +57 -0
  79. data/lib/core_ext/logger_silence.rb +24 -0
  80. data/lib/core_ext/marshal.rb +19 -0
  81. data/lib/core_ext/module/aliasing.rb +74 -0
  82. data/lib/core_ext/module/anonymous.rb +28 -0
  83. data/lib/core_ext/module/attr_internal.rb +36 -0
  84. data/lib/core_ext/module/attribute_accessors.rb +212 -0
  85. data/lib/core_ext/module/concerning.rb +135 -0
  86. data/lib/core_ext/module/delegation.rb +218 -0
  87. data/lib/core_ext/module/deprecation.rb +23 -0
  88. data/lib/core_ext/module/introspection.rb +62 -0
  89. data/lib/core_ext/module/method_transplanting.rb +3 -0
  90. data/lib/core_ext/module/qualified_const.rb +52 -0
  91. data/lib/core_ext/module/reachable.rb +8 -0
  92. data/lib/core_ext/module/remove_method.rb +35 -0
  93. data/lib/core_ext/module.rb +11 -0
  94. data/lib/core_ext/multibyte/chars.rb +231 -0
  95. data/lib/core_ext/multibyte/unicode.rb +388 -0
  96. data/lib/core_ext/multibyte.rb +21 -0
  97. data/lib/core_ext/name_error.rb +31 -0
  98. data/lib/core_ext/numeric/bytes.rb +64 -0
  99. data/lib/core_ext/numeric/conversions.rb +132 -0
  100. data/lib/core_ext/numeric/inquiry.rb +26 -0
  101. data/lib/core_ext/numeric/time.rb +74 -0
  102. data/lib/core_ext/numeric.rb +4 -0
  103. data/lib/core_ext/object/acts_like.rb +10 -0
  104. data/lib/core_ext/object/blank.rb +140 -0
  105. data/lib/core_ext/object/conversions.rb +4 -0
  106. data/lib/core_ext/object/deep_dup.rb +53 -0
  107. data/lib/core_ext/object/duplicable.rb +98 -0
  108. data/lib/core_ext/object/inclusion.rb +27 -0
  109. data/lib/core_ext/object/instance_variables.rb +28 -0
  110. data/lib/core_ext/object/json.rb +199 -0
  111. data/lib/core_ext/object/to_param.rb +1 -0
  112. data/lib/core_ext/object/to_query.rb +84 -0
  113. data/lib/core_ext/object/try.rb +146 -0
  114. data/lib/core_ext/object/with_options.rb +69 -0
  115. data/lib/core_ext/object.rb +14 -0
  116. data/lib/core_ext/option_merger.rb +25 -0
  117. data/lib/core_ext/ordered_hash.rb +48 -0
  118. data/lib/core_ext/ordered_options.rb +81 -0
  119. data/lib/core_ext/range/conversions.rb +34 -0
  120. data/lib/core_ext/range/each.rb +21 -0
  121. data/lib/core_ext/range/include_range.rb +23 -0
  122. data/lib/core_ext/range/overlaps.rb +8 -0
  123. data/lib/core_ext/range.rb +4 -0
  124. data/lib/core_ext/regexp.rb +5 -0
  125. data/lib/core_ext/rescuable.rb +119 -0
  126. data/lib/core_ext/securerandom.rb +23 -0
  127. data/lib/core_ext/security_utils.rb +20 -0
  128. data/lib/core_ext/string/access.rb +104 -0
  129. data/lib/core_ext/string/behavior.rb +6 -0
  130. data/lib/core_ext/string/conversions.rb +56 -0
  131. data/lib/core_ext/string/exclude.rb +11 -0
  132. data/lib/core_ext/string/filters.rb +102 -0
  133. data/lib/core_ext/string/indent.rb +43 -0
  134. data/lib/core_ext/string/inflections.rb +235 -0
  135. data/lib/core_ext/string/inquiry.rb +13 -0
  136. data/lib/core_ext/string/multibyte.rb +53 -0
  137. data/lib/core_ext/string/output_safety.rb +261 -0
  138. data/lib/core_ext/string/starts_ends_with.rb +4 -0
  139. data/lib/core_ext/string/strip.rb +23 -0
  140. data/lib/core_ext/string/zones.rb +14 -0
  141. data/lib/core_ext/string.rb +13 -0
  142. data/lib/core_ext/string_inquirer.rb +26 -0
  143. data/lib/core_ext/tagged_logging.rb +78 -0
  144. data/lib/core_ext/test_case.rb +88 -0
  145. data/lib/core_ext/testing/assertions.rb +99 -0
  146. data/lib/core_ext/testing/autorun.rb +12 -0
  147. data/lib/core_ext/testing/composite_filter.rb +54 -0
  148. data/lib/core_ext/testing/constant_lookup.rb +50 -0
  149. data/lib/core_ext/testing/declarative.rb +26 -0
  150. data/lib/core_ext/testing/deprecation.rb +36 -0
  151. data/lib/core_ext/testing/file_fixtures.rb +34 -0
  152. data/lib/core_ext/testing/isolation.rb +115 -0
  153. data/lib/core_ext/testing/method_call_assertions.rb +41 -0
  154. data/lib/core_ext/testing/setup_and_teardown.rb +50 -0
  155. data/lib/core_ext/testing/stream.rb +42 -0
  156. data/lib/core_ext/testing/tagged_logging.rb +25 -0
  157. data/lib/core_ext/testing/time_helpers.rb +134 -0
  158. data/lib/core_ext/time/acts_like.rb +8 -0
  159. data/lib/core_ext/time/calculations.rb +284 -0
  160. data/lib/core_ext/time/conversions.rb +66 -0
  161. data/lib/core_ext/time/zones.rb +95 -0
  162. data/lib/core_ext/time.rb +20 -0
  163. data/lib/core_ext/time_with_zone.rb +503 -0
  164. data/lib/core_ext/time_zone.rb +464 -0
  165. data/lib/core_ext/uri.rb +25 -0
  166. data/lib/core_ext/version.rb +3 -0
  167. data/lib/core_ext/xml_mini/jdom.rb +181 -0
  168. data/lib/core_ext/xml_mini/libxml.rb +79 -0
  169. data/lib/core_ext/xml_mini/libxmlsax.rb +85 -0
  170. data/lib/core_ext/xml_mini/nokogiri.rb +83 -0
  171. data/lib/core_ext/xml_mini/nokogirisax.rb +87 -0
  172. data/lib/core_ext/xml_mini/rexml.rb +130 -0
  173. data/lib/core_ext/xml_mini.rb +194 -0
  174. data/lib/core_ext.rb +3 -0
  175. metadata +310 -0
@@ -0,0 +1,93 @@
1
+ require 'date'
2
+ require 'core_ext/date/zones'
3
+ require 'core_ext/module/remove_method'
4
+
5
+ class Date
6
+ DATE_FORMATS = {
7
+ :short => '%e %b',
8
+ :long => '%B %e, %Y',
9
+ :db => '%Y-%m-%d',
10
+ :number => '%Y%m%d',
11
+ :long_ordinal => lambda { |date|
12
+ day_format = CoreExt::Inflector.ordinalize(date.day)
13
+ date.strftime("%B #{day_format}, %Y") # => "April 25th, 2007"
14
+ },
15
+ :rfc822 => '%e %b %Y',
16
+ :iso8601 => lambda { |date| date.iso8601 }
17
+ }
18
+
19
+ # Ruby 1.9 has Date#to_time which converts to localtime only.
20
+ remove_method :to_time
21
+
22
+ # Ruby 1.9 has Date#xmlschema which converts to a string without the time
23
+ # component. This removal may generate an issue on FreeBSD, that's why we
24
+ # need to use remove_possible_method here
25
+ remove_possible_method :xmlschema
26
+
27
+ # Convert to a formatted string. See DATE_FORMATS for predefined formats.
28
+ #
29
+ # This method is aliased to <tt>to_s</tt>.
30
+ #
31
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
32
+ #
33
+ # date.to_formatted_s(:db) # => "2007-11-10"
34
+ # date.to_s(:db) # => "2007-11-10"
35
+ #
36
+ # date.to_formatted_s(:short) # => "10 Nov"
37
+ # date.to_formatted_s(:number) # => "20071110"
38
+ # date.to_formatted_s(:long) # => "November 10, 2007"
39
+ # date.to_formatted_s(:long_ordinal) # => "November 10th, 2007"
40
+ # date.to_formatted_s(:rfc822) # => "10 Nov 2007"
41
+ # date.to_formatted_s(:iso8601) # => "2007-11-10"
42
+ #
43
+ # == Adding your own date formats to to_formatted_s
44
+ # You can add your own formats to the Date::DATE_FORMATS hash.
45
+ # Use the format name as the hash key and either a strftime string
46
+ # or Proc instance that takes a date argument as the value.
47
+ #
48
+ # # config/initializers/date_formats.rb
49
+ # Date::DATE_FORMATS[:month_and_year] = '%B %Y'
50
+ # Date::DATE_FORMATS[:short_ordinal] = ->(date) { date.strftime("%B #{date.day.ordinalize}") }
51
+ def to_formatted_s(format = :default)
52
+ if formatter = DATE_FORMATS[format]
53
+ if formatter.respond_to?(:call)
54
+ formatter.call(self).to_s
55
+ else
56
+ strftime(formatter)
57
+ end
58
+ else
59
+ to_default_s
60
+ end
61
+ end
62
+ alias_method :to_default_s, :to_s
63
+ alias_method :to_s, :to_formatted_s
64
+
65
+ # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
66
+ def readable_inspect
67
+ strftime('%a, %d %b %Y')
68
+ end
69
+ alias_method :default_inspect, :inspect
70
+ alias_method :inspect, :readable_inspect
71
+
72
+ # Converts a Date instance to a Time, where the time is set to the beginning of the day.
73
+ # The timezone can be either :local or :utc (default :local).
74
+ #
75
+ # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
76
+ #
77
+ # date.to_time # => 2007-11-10 00:00:00 0800
78
+ # date.to_time(:local) # => 2007-11-10 00:00:00 0800
79
+ #
80
+ # date.to_time(:utc) # => 2007-11-10 00:00:00 UTC
81
+ def to_time(form = :local)
82
+ ::Time.send(form, year, month, day)
83
+ end
84
+
85
+ # Returns a string which represents the time in used time zone as DateTime
86
+ # defined by XML Schema:
87
+ #
88
+ # date = Date.new(2015, 05, 23) # => Sat, 23 May 2015
89
+ # date.xmlschema # => "2015-05-23T00:00:00+04:00"
90
+ def xmlschema
91
+ in_time_zone.xmlschema
92
+ end
93
+ end
@@ -0,0 +1,6 @@
1
+ require 'date'
2
+ require 'core_ext/date_and_time/zones'
3
+
4
+ class Date
5
+ include DateAndTime::Zones
6
+ end
@@ -0,0 +1,5 @@
1
+ require 'core_ext/date/acts_like'
2
+ require 'core_ext/date/blank'
3
+ require 'core_ext/date/calculations'
4
+ require 'core_ext/date/conversions'
5
+ require 'core_ext/date/zones'
@@ -0,0 +1,328 @@
1
+ module DateAndTime
2
+ module Calculations
3
+ DAYS_INTO_WEEK = {
4
+ :monday => 0,
5
+ :tuesday => 1,
6
+ :wednesday => 2,
7
+ :thursday => 3,
8
+ :friday => 4,
9
+ :saturday => 5,
10
+ :sunday => 6
11
+ }
12
+ WEEKEND_DAYS = [ 6, 0 ]
13
+
14
+ # Returns a new date/time representing yesterday.
15
+ def yesterday
16
+ advance(days: -1)
17
+ end
18
+
19
+ # Returns a new date/time representing the previous day.
20
+ def prev_day
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 a new date/time representing the next day.
30
+ def next_day
31
+ advance(days: 1)
32
+ end
33
+
34
+ # Returns true if the date/time is today.
35
+ def today?
36
+ to_date == ::Date.current
37
+ end
38
+
39
+ # Returns true if the date/time is in the past.
40
+ def past?
41
+ self < self.class.current
42
+ end
43
+
44
+ # Returns true if the date/time is in the future.
45
+ def future?
46
+ self > self.class.current
47
+ end
48
+
49
+ # Returns true if the date/time falls on a Saturday or Sunday.
50
+ def on_weekend?
51
+ WEEKEND_DAYS.include?(wday)
52
+ end
53
+
54
+ # Returns a new date/time the specified number of days ago.
55
+ def days_ago(days)
56
+ advance(:days => -days)
57
+ end
58
+
59
+ # Returns a new date/time the specified number of days in the future.
60
+ def days_since(days)
61
+ advance(:days => days)
62
+ end
63
+
64
+ # Returns a new date/time the specified number of weeks ago.
65
+ def weeks_ago(weeks)
66
+ advance(:weeks => -weeks)
67
+ end
68
+
69
+ # Returns a new date/time the specified number of weeks in the future.
70
+ def weeks_since(weeks)
71
+ advance(:weeks => weeks)
72
+ end
73
+
74
+ # Returns a new date/time the specified number of months ago.
75
+ def months_ago(months)
76
+ advance(:months => -months)
77
+ end
78
+
79
+ # Returns a new date/time the specified number of months in the future.
80
+ def months_since(months)
81
+ advance(:months => months)
82
+ end
83
+
84
+ # Returns a new date/time the specified number of years ago.
85
+ def years_ago(years)
86
+ advance(:years => -years)
87
+ end
88
+
89
+ # Returns a new date/time the specified number of years in the future.
90
+ def years_since(years)
91
+ advance(:years => years)
92
+ end
93
+
94
+ # Returns a new date/time at the start of the month.
95
+ #
96
+ # today = Date.today # => Thu, 18 Jun 2015
97
+ # today.beginning_of_month # => Mon, 01 Jun 2015
98
+ #
99
+ # +DateTime+ objects will have a time set to 0:00.
100
+ #
101
+ # now = DateTime.current # => Thu, 18 Jun 2015 15:23:13 +0000
102
+ # now.beginning_of_month # => Mon, 01 Jun 2015 00:00:00 +0000
103
+ def beginning_of_month
104
+ first_hour(change(:day => 1))
105
+ end
106
+ alias :at_beginning_of_month :beginning_of_month
107
+
108
+ # Returns a new date/time at the start of the quarter.
109
+ #
110
+ # today = Date.today # => Fri, 10 Jul 2015
111
+ # today.beginning_of_quarter # => Wed, 01 Jul 2015
112
+ #
113
+ # +DateTime+ objects will have a time set to 0:00.
114
+ #
115
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
116
+ # now.beginning_of_quarter # => Wed, 01 Jul 2015 00:00:00 +0000
117
+ def beginning_of_quarter
118
+ first_quarter_month = [10, 7, 4, 1].detect { |m| m <= month }
119
+ beginning_of_month.change(:month => first_quarter_month)
120
+ end
121
+ alias :at_beginning_of_quarter :beginning_of_quarter
122
+
123
+ # Returns a new date/time at the end of the quarter.
124
+ #
125
+ # today = Date.today # => Fri, 10 Jul 2015
126
+ # today.end_of_quarter # => Wed, 30 Sep 2015
127
+ #
128
+ # +DateTime+ objects will have a time set to 23:59:59.
129
+ #
130
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
131
+ # now.end_of_quarter # => Wed, 30 Sep 2015 23:59:59 +0000
132
+ def end_of_quarter
133
+ last_quarter_month = [3, 6, 9, 12].detect { |m| m >= month }
134
+ beginning_of_month.change(:month => last_quarter_month).end_of_month
135
+ end
136
+ alias :at_end_of_quarter :end_of_quarter
137
+
138
+ # Returns a new date/time at the beginning of the year.
139
+ #
140
+ # today = Date.today # => Fri, 10 Jul 2015
141
+ # today.beginning_of_year # => Thu, 01 Jan 2015
142
+ #
143
+ # +DateTime+ objects will have a time set to 0:00.
144
+ #
145
+ # now = DateTime.current # => Fri, 10 Jul 2015 18:41:29 +0000
146
+ # now.beginning_of_year # => Thu, 01 Jan 2015 00:00:00 +0000
147
+ def beginning_of_year
148
+ change(:month => 1).beginning_of_month
149
+ end
150
+ alias :at_beginning_of_year :beginning_of_year
151
+
152
+ # Returns a new date/time representing the given day in the next week.
153
+ #
154
+ # today = Date.today # => Thu, 07 May 2015
155
+ # today.next_week # => Mon, 11 May 2015
156
+ #
157
+ # The +given_day_in_next_week+ defaults to the beginning of the week
158
+ # which is determined by +Date.beginning_of_week+ or +config.beginning_of_week+
159
+ # when set.
160
+ #
161
+ # today = Date.today # => Thu, 07 May 2015
162
+ # today.next_week(:friday) # => Fri, 15 May 2015
163
+ #
164
+ # +DateTime+ objects have their time set to 0:00 unless +same_time+ is true.
165
+ #
166
+ # now = DateTime.current # => Thu, 07 May 2015 13:31:16 +0000
167
+ # now.next_week # => Mon, 11 May 2015 00:00:00 +0000
168
+ def next_week(given_day_in_next_week = Date.beginning_of_week, same_time: false)
169
+ result = first_hour(weeks_since(1).beginning_of_week.days_since(days_span(given_day_in_next_week)))
170
+ same_time ? copy_time_to(result) : result
171
+ end
172
+
173
+ # Returns a new date/time representing the next weekday.
174
+ def next_weekday
175
+ if next_day.on_weekend?
176
+ next_week(:monday, same_time: true)
177
+ else
178
+ next_day
179
+ end
180
+ end
181
+
182
+ # Short-hand for months_since(1).
183
+ def next_month
184
+ months_since(1)
185
+ end
186
+
187
+ # Short-hand for months_since(3)
188
+ def next_quarter
189
+ months_since(3)
190
+ end
191
+
192
+ # Short-hand for years_since(1).
193
+ def next_year
194
+ years_since(1)
195
+ end
196
+
197
+ # Returns a new date/time representing the given day in the previous week.
198
+ # Week is assumed to start on +start_day+, default is
199
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
200
+ # DateTime objects have their time set to 0:00 unless +same_time+ is true.
201
+ def prev_week(start_day = Date.beginning_of_week, same_time: false)
202
+ result = first_hour(weeks_ago(1).beginning_of_week.days_since(days_span(start_day)))
203
+ same_time ? copy_time_to(result) : result
204
+ end
205
+ alias_method :last_week, :prev_week
206
+
207
+ # Returns a new date/time representing the previous weekday.
208
+ def prev_weekday
209
+ if prev_day.on_weekend?
210
+ copy_time_to(beginning_of_week(:friday))
211
+ else
212
+ prev_day
213
+ end
214
+ end
215
+ alias_method :last_weekday, :prev_weekday
216
+
217
+ # Short-hand for months_ago(1).
218
+ def prev_month
219
+ months_ago(1)
220
+ end
221
+ alias_method :last_month, :prev_month
222
+
223
+ # Short-hand for months_ago(3).
224
+ def prev_quarter
225
+ months_ago(3)
226
+ end
227
+ alias_method :last_quarter, :prev_quarter
228
+
229
+ # Short-hand for years_ago(1).
230
+ def prev_year
231
+ years_ago(1)
232
+ end
233
+ alias_method :last_year, :prev_year
234
+
235
+ # Returns the number of days to the start of the week on the given day.
236
+ # Week is assumed to start on +start_day+, default is
237
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
238
+ def days_to_week_start(start_day = Date.beginning_of_week)
239
+ start_day_number = DAYS_INTO_WEEK[start_day]
240
+ current_day_number = wday != 0 ? wday - 1 : 6
241
+ (current_day_number - start_day_number) % 7
242
+ end
243
+
244
+ # Returns a new date/time representing the start of this week on the given day.
245
+ # Week is assumed to start on +start_day+, default is
246
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
247
+ # +DateTime+ objects have their time set to 0:00.
248
+ def beginning_of_week(start_day = Date.beginning_of_week)
249
+ result = days_ago(days_to_week_start(start_day))
250
+ acts_like?(:time) ? result.midnight : result
251
+ end
252
+ alias :at_beginning_of_week :beginning_of_week
253
+
254
+ # Returns Monday of this week assuming that week starts on Monday.
255
+ # +DateTime+ objects have their time set to 0:00.
256
+ def monday
257
+ beginning_of_week(:monday)
258
+ end
259
+
260
+ # Returns a new date/time representing the end of this week on the given day.
261
+ # Week is assumed to start on +start_day+, default is
262
+ # +Date.beginning_of_week+ or +config.beginning_of_week+ when set.
263
+ # DateTime objects have their time set to 23:59:59.
264
+ def end_of_week(start_day = Date.beginning_of_week)
265
+ last_hour(days_since(6 - days_to_week_start(start_day)))
266
+ end
267
+ alias :at_end_of_week :end_of_week
268
+
269
+ # Returns Sunday of this week assuming that week starts on Monday.
270
+ # +DateTime+ objects have their time set to 23:59:59.
271
+ def sunday
272
+ end_of_week(:monday)
273
+ end
274
+
275
+ # Returns a new date/time representing the end of the month.
276
+ # DateTime objects will have a time set to 23:59:59.
277
+ def end_of_month
278
+ last_day = ::Time.days_in_month(month, year)
279
+ last_hour(days_since(last_day - day))
280
+ end
281
+ alias :at_end_of_month :end_of_month
282
+
283
+ # Returns a new date/time representing the end of the year.
284
+ # DateTime objects will have a time set to 23:59:59.
285
+ def end_of_year
286
+ change(:month => 12).end_of_month
287
+ end
288
+ alias :at_end_of_year :end_of_year
289
+
290
+ # Returns a Range representing the whole week of the current date/time.
291
+ # Week starts on start_day, default is <tt>Date.week_start</tt> or <tt>config.week_start</tt> when set.
292
+ def all_week(start_day = Date.beginning_of_week)
293
+ beginning_of_week(start_day)..end_of_week(start_day)
294
+ end
295
+
296
+ # Returns a Range representing the whole month of the current date/time.
297
+ def all_month
298
+ beginning_of_month..end_of_month
299
+ end
300
+
301
+ # Returns a Range representing the whole quarter of the current date/time.
302
+ def all_quarter
303
+ beginning_of_quarter..end_of_quarter
304
+ end
305
+
306
+ # Returns a Range representing the whole year of the current date/time.
307
+ def all_year
308
+ beginning_of_year..end_of_year
309
+ end
310
+
311
+ private
312
+ def first_hour(date_or_time)
313
+ date_or_time.acts_like?(:time) ? date_or_time.beginning_of_day : date_or_time
314
+ end
315
+
316
+ def last_hour(date_or_time)
317
+ date_or_time.acts_like?(:time) ? date_or_time.end_of_day : date_or_time
318
+ end
319
+
320
+ def days_span(day)
321
+ (DAYS_INTO_WEEK[day] - DAYS_INTO_WEEK[Date.beginning_of_week]) % 7
322
+ end
323
+
324
+ def copy_time_to(other)
325
+ other.change(hour: hour, min: min, sec: sec, usec: try(:usec))
326
+ end
327
+ end
328
+ end
@@ -0,0 +1,40 @@
1
+ module DateAndTime
2
+ module Zones
3
+ # Returns the simultaneous time in <tt>Time.zone</tt> if a zone is given or
4
+ # if Time.zone_default is set. Otherwise, it returns the current time.
5
+ #
6
+ # Time.zone = 'Hawaii' # => 'Hawaii'
7
+ # Time.utc(2000).in_time_zone # => Fri, 31 Dec 1999 14:00:00 HST -10:00
8
+ # Date.new(2000).in_time_zone # => Sat, 01 Jan 2000 00:00:00 HST -10:00
9
+ #
10
+ # This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
11
+ # instead of the operating system's time zone.
12
+ #
13
+ # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
14
+ # and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
15
+ #
16
+ # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
17
+ # Date.new(2000).in_time_zone('Alaska') # => Sat, 01 Jan 2000 00:00:00 AKST -09:00
18
+ def in_time_zone(zone = ::Time.zone)
19
+ time_zone = ::Time.find_zone! zone
20
+ time = acts_like?(:time) ? self : nil
21
+
22
+ if time_zone
23
+ time_with_zone(time, time_zone)
24
+ else
25
+ time || self.to_time
26
+ end
27
+ end
28
+
29
+ private
30
+
31
+ def time_with_zone(time, zone)
32
+ if time
33
+ CoreExt::TimeWithZone.new(time.utc? ? time : time.getutc, zone)
34
+ else
35
+ CoreExt::TimeWithZone.new(nil, zone, to_time(:utc))
36
+ end
37
+ end
38
+ end
39
+ end
40
+
@@ -0,0 +1,14 @@
1
+ require 'date'
2
+ require 'core_ext/object/acts_like'
3
+
4
+ class DateTime
5
+ # Duck-types as a Date-like class. See Object#acts_like?.
6
+ def acts_like_date?
7
+ true
8
+ end
9
+
10
+ # Duck-types as a Time-like class. See Object#acts_like?.
11
+ def acts_like_time?
12
+ true
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ require 'date'
2
+
3
+ class DateTime #:nodoc:
4
+ # No DateTime is ever blank:
5
+ #
6
+ # DateTime.now.blank? # => false
7
+ #
8
+ # @return [false]
9
+ def blank?
10
+ false
11
+ end
12
+ end
@@ -0,0 +1,177 @@
1
+ require 'date'
2
+
3
+ class DateTime
4
+ class << self
5
+ # Returns <tt>Time.zone.now.to_datetime</tt> when <tt>Time.zone</tt> or
6
+ # <tt>config.time_zone</tt> are set, otherwise returns
7
+ # <tt>Time.now.to_datetime</tt>.
8
+ def current
9
+ ::Time.zone ? ::Time.zone.now.to_datetime : ::Time.now.to_datetime
10
+ end
11
+ end
12
+
13
+ # Returns the number of seconds since 00:00:00.
14
+ #
15
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
16
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
17
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
18
+ def seconds_since_midnight
19
+ sec + (min * 60) + (hour * 3600)
20
+ end
21
+
22
+ # Returns the number of seconds until 23:59:59.
23
+ #
24
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_until_end_of_day # => 86399
25
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_until_end_of_day # => 41103
26
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_until_end_of_day # => 0
27
+ def seconds_until_end_of_day
28
+ end_of_day.to_i - to_i
29
+ end
30
+
31
+ # Returns a new DateTime where one or more of the elements have been changed
32
+ # according to the +options+ parameter. The time options (<tt>:hour</tt>,
33
+ # <tt>:min</tt>, <tt>:sec</tt>) reset cascadingly, so if only the hour is
34
+ # passed, then minute and sec is set to 0. If the hour and minute is passed,
35
+ # then sec is set to 0. The +options+ parameter takes a hash with any of these
36
+ # keys: <tt>:year</tt>, <tt>:month</tt>, <tt>:day</tt>, <tt>:hour</tt>,
37
+ # <tt>:min</tt>, <tt>:sec</tt>, <tt>:offset</tt>, <tt>:start</tt>.
38
+ #
39
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(day: 1) # => DateTime.new(2012, 8, 1, 22, 35, 0)
40
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => DateTime.new(1981, 8, 1, 22, 35, 0)
41
+ # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
42
+ def change(options)
43
+ ::DateTime.civil(
44
+ options.fetch(:year, year),
45
+ options.fetch(:month, month),
46
+ options.fetch(:day, day),
47
+ options.fetch(:hour, hour),
48
+ options.fetch(:min, options[:hour] ? 0 : min),
49
+ options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec + sec_fraction),
50
+ options.fetch(:offset, offset),
51
+ options.fetch(:start, start)
52
+ )
53
+ end
54
+
55
+ # Uses Date to provide precise Time calculations for years, months, and days.
56
+ # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
57
+ # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
58
+ # <tt>:minutes</tt>, <tt>:seconds</tt>.
59
+ def advance(options)
60
+ unless options[:weeks].nil?
61
+ options[:weeks], partial_weeks = options[:weeks].divmod(1)
62
+ options[:days] = options.fetch(:days, 0) + 7 * partial_weeks
63
+ end
64
+
65
+ unless options[:days].nil?
66
+ options[:days], partial_days = options[:days].divmod(1)
67
+ options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
68
+ end
69
+
70
+ d = to_date.advance(options)
71
+ datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
72
+ seconds_to_advance = \
73
+ options.fetch(:seconds, 0) +
74
+ options.fetch(:minutes, 0) * 60 +
75
+ options.fetch(:hours, 0) * 3600
76
+
77
+ if seconds_to_advance.zero?
78
+ datetime_advanced_by_date
79
+ else
80
+ datetime_advanced_by_date.since(seconds_to_advance)
81
+ end
82
+ end
83
+
84
+ # Returns a new DateTime representing the time a number of seconds ago.
85
+ # Do not use this method in combination with x.months, use months_ago instead!
86
+ def ago(seconds)
87
+ since(-seconds)
88
+ end
89
+
90
+ # Returns a new DateTime representing the time a number of seconds since the
91
+ # instance time. Do not use this method in combination with x.months, use
92
+ # months_since instead!
93
+ def since(seconds)
94
+ self + Rational(seconds.round, 86400)
95
+ end
96
+ alias :in :since
97
+
98
+ # Returns a new DateTime representing the start of the day (0:00).
99
+ def beginning_of_day
100
+ change(:hour => 0)
101
+ end
102
+ alias :midnight :beginning_of_day
103
+ alias :at_midnight :beginning_of_day
104
+ alias :at_beginning_of_day :beginning_of_day
105
+
106
+ # Returns a new DateTime representing the middle of the day (12:00)
107
+ def middle_of_day
108
+ change(:hour => 12)
109
+ end
110
+ alias :midday :middle_of_day
111
+ alias :noon :middle_of_day
112
+ alias :at_midday :middle_of_day
113
+ alias :at_noon :middle_of_day
114
+ alias :at_middle_of_day :middle_of_day
115
+
116
+ # Returns a new DateTime representing the end of the day (23:59:59).
117
+ def end_of_day
118
+ change(:hour => 23, :min => 59, :sec => 59)
119
+ end
120
+ alias :at_end_of_day :end_of_day
121
+
122
+ # Returns a new DateTime representing the start of the hour (hh:00:00).
123
+ def beginning_of_hour
124
+ change(:min => 0)
125
+ end
126
+ alias :at_beginning_of_hour :beginning_of_hour
127
+
128
+ # Returns a new DateTime representing the end of the hour (hh:59:59).
129
+ def end_of_hour
130
+ change(:min => 59, :sec => 59)
131
+ end
132
+ alias :at_end_of_hour :end_of_hour
133
+
134
+ # Returns a new DateTime representing the start of the minute (hh:mm:00).
135
+ def beginning_of_minute
136
+ change(:sec => 0)
137
+ end
138
+ alias :at_beginning_of_minute :beginning_of_minute
139
+
140
+ # Returns a new DateTime representing the end of the minute (hh:mm:59).
141
+ def end_of_minute
142
+ change(:sec => 59)
143
+ end
144
+ alias :at_end_of_minute :end_of_minute
145
+
146
+ # Adjusts DateTime to UTC by adding its offset value; offset is set to 0.
147
+ #
148
+ # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
149
+ # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 +0000
150
+ def utc
151
+ new_offset(0)
152
+ end
153
+ alias_method :getutc, :utc
154
+
155
+ # Returns +true+ if <tt>offset == 0</tt>.
156
+ def utc?
157
+ offset == 0
158
+ end
159
+
160
+ # Returns the offset value in seconds.
161
+ def utc_offset
162
+ (offset * 86400).to_i
163
+ end
164
+
165
+ # Layers additional behavior on DateTime#<=> so that Time and
166
+ # CoreExt::TimeWithZone instances can be compared with a DateTime.
167
+ def <=>(other)
168
+ if other.kind_of?(Infinity)
169
+ super
170
+ elsif other.respond_to? :to_datetime
171
+ super other.to_datetime rescue nil
172
+ else
173
+ nil
174
+ end
175
+ end
176
+
177
+ end