Module: IceCube::TimeUtil
- Extended by:
- Deprecated
- Defined in:
- lib/ice_cube/time_util.rb
Defined Under Namespace
Classes: TimeWrapper
Constant Summary collapse
- DAYS =
{ sunday: 0, monday: 1, tuesday: 2, wednesday: 3, thursday: 4, friday: 5, saturday: 6 }
- ICAL_DAYS =
{ "SU" => :sunday, "MO" => :monday, "TU" => :tuesday, "WE" => :wednesday, "TH" => :thursday, "FR" => :friday, "SA" => :saturday }
- MONTHS =
{ january: 1, february: 2, march: 3, april: 4, may: 5, june: 6, july: 7, august: 8, september: 9, october: 10, november: 11, december: 12 }
- CLOCK_VALUES =
[:year, :month, :day, :hour, :min, :sec]
Class Method Summary collapse
-
.beginning_of_date(date, reference = Time.now) ⇒ Object
Get the beginning of a date.
- .build_in_zone(args, reference) ⇒ Object
-
.day_of_month(value, date) ⇒ Object
Get a day of the month in the month of a given time without overflowing into the next month.
-
.days_in_month(time) ⇒ Object
Get the days in the month for +time.
-
.days_in_n_months(time, month_distance) ⇒ Object
The number of days in n months.
-
.days_in_n_years(time, year_distance) ⇒ Object
Number of days to n years.
-
.days_in_next_month(time) ⇒ Object
Get the days in the following month for +time.
-
.days_in_year(time) ⇒ Object
Number of days in a year.
-
.days_to_next_month(time) ⇒ Object
Count the number of days to the same day of the next month without overflowing shorter months.
-
.deserialize_time(time_or_hash) ⇒ Object
Deserialize a time serialized with serialize_time or in ISO8601 string format.
- .dst_change(time) ⇒ Object
-
.end_of_date(date, reference = Time.now) ⇒ Object
Get the end of a date.
-
.ensure_date(date) ⇒ Object
Ensure that this is either nil, or a date.
-
.ensure_time(time, reference = nil, date_eod = false) ⇒ Object
Ensure that this is either nil, or a time.
-
.hash(time) ⇒ Object
Get a more precise equality for time objects Ruby provides a Time#hash method, but it fails to account for UTC offset (so the current date may be different) or DST rules (so the hour may be wrong for different schedule occurrences).
- .ical_day_to_symbol(str) ⇒ Object
- .match_zone(input_time, reference) ⇒ Object
-
.normalize_wday(wday, week_start) ⇒ Object
Convert weekday from base sunday to the schedule’s week start.
-
.now(reference = Time.now) ⇒ Object
Provides a Time.now without the usec, in the reference zone or utc offset.
-
.restore_deserialized_offset(time, orig_offset_str) ⇒ Object
Check the deserialized time offset string against actual local time offset to try and preserve the original offset for plain Ruby Time.
-
.serialize_time(time) ⇒ Object
Serialize a time appropriate for storing.
-
.subsec(time) ⇒ Object
Handle discrepancies between various time types - Time has subsec - DateTime does not - ActiveSupport::TimeWithZone can wrap either type, depending on version or if ‘parse` or `now`/`local` was used to build it.
-
.sym_to_month(sym) ⇒ Object
Convert a symbol to a numeric month.
-
.sym_to_wday(sym) ⇒ Object
Convert a symbol to a wday number.
-
.wday_to_sym(wday) ⇒ Object
Convert wday number to day symbol.
-
.which_occurrence_in_month(time, wday) ⇒ Object
Return the count of the number of times wday appears in the month, and which of those time falls on.
Methods included from Deprecated
deprecated, deprecated_alias, schedule_options
Class Method Details
.beginning_of_date(date, reference = Time.now) ⇒ Object
Get the beginning of a date
137 138 139 |
# File 'lib/ice_cube/time_util.rb', line 137 def self.beginning_of_date(date, reference = Time.now) build_in_zone([date.year, date.month, date.day, 0, 0, 0], reference) end |
.build_in_zone(args, reference) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 |
# File 'lib/ice_cube/time_util.rb', line 31 def self.build_in_zone(args, reference) if reference.respond_to?(:time_zone) reference.time_zone.local(*args) elsif reference.utc? Time.utc(*args) elsif reference.zone Time.local(*args) else Time.new(*args << reference.utc_offset) end end |
.day_of_month(value, date) ⇒ Object
Get a day of the month in the month of a given time without overflowing into the next month. Accepts days from positive (start of month forward) or negative (from end of month)
218 219 220 221 222 223 224 |
# File 'lib/ice_cube/time_util.rb', line 218 def self.day_of_month(value, date) if value.to_i > 0 [value, days_in_month(date)].min else [1 + days_in_month(date) + value, 1].max end end |
.days_in_month(time) ⇒ Object
Get the days in the month for +time
197 198 199 200 |
# File 'lib/ice_cube/time_util.rb', line 197 def self.days_in_month(time) date = Date.new(time.year, time.month, 1) ((date >> 1) - date).to_i end |
.days_in_n_months(time, month_distance) ⇒ Object
The number of days in n months
239 240 241 242 |
# File 'lib/ice_cube/time_util.rb', line 239 def self.days_in_n_months(time, month_distance) date = Date.new(time.year, time.month, time.day) ((date >> month_distance) - date).to_i end |
.days_in_n_years(time, year_distance) ⇒ Object
Number of days to n years
233 234 235 236 |
# File 'lib/ice_cube/time_util.rb', line 233 def self.days_in_n_years(time, year_distance) date = Date.new(time.year, time.month, time.day) ((date >> year_distance * 12) - date).to_i end |
.days_in_next_month(time) ⇒ Object
Get the days in the following month for +time
203 204 205 206 |
# File 'lib/ice_cube/time_util.rb', line 203 def self.days_in_next_month(time) date = Date.new(time.year, time.month, 1) >> 1 ((date >> 1) - date).to_i end |
.days_in_year(time) ⇒ Object
Number of days in a year
227 228 229 230 |
# File 'lib/ice_cube/time_util.rb', line 227 def self.days_in_year(time) date = Date.new(time.year, 1, 1) ((date >> 12) - date).to_i end |
.days_to_next_month(time) ⇒ Object
Count the number of days to the same day of the next month without overflowing shorter months
210 211 212 213 |
# File 'lib/ice_cube/time_util.rb', line 210 def self.days_to_next_month(time) date = Date.new(time.year, time.month, time.day) ((date >> 1) - date).to_i end |
.deserialize_time(time_or_hash) ⇒ Object
Deserialize a time serialized with serialize_time or in ISO8601 string format
102 103 104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/ice_cube/time_util.rb', line 102 def self.deserialize_time(time_or_hash) case time_or_hash when Time, Date time_or_hash when DateTime Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec) when Hash hash = FlexibleHash.new(time_or_hash) hash[:time].in_time_zone(hash[:zone]) when String Time.parse(time_or_hash) end end |
.dst_change(time) ⇒ Object
244 245 246 247 248 249 |
# File 'lib/ice_cube/time_util.rb', line 244 def self.dst_change(time) one_hour_ago = time - ONE_HOUR if time.dst? ^ one_hour_ago.dst? (time.utc_offset - one_hour_ago.utc_offset) / ONE_HOUR end end |
.end_of_date(date, reference = Time.now) ⇒ Object
Get the end of a date
142 143 144 |
# File 'lib/ice_cube/time_util.rb', line 142 def self.end_of_date(date, reference = Time.now) build_in_zone([date.year, date.month, date.day, 23, 59, 59], reference) end |
.ensure_date(date) ⇒ Object
Ensure that this is either nil, or a date
77 78 79 80 81 82 83 |
# File 'lib/ice_cube/time_util.rb', line 77 def self.ensure_date(date) case date when Date then date else Date.new(date.year, date.month, date.day) end end |
.ensure_time(time, reference = nil, date_eod = false) ⇒ Object
Ensure that this is either nil, or a time
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/ice_cube/time_util.rb', line 58 def self.ensure_time(time, reference = nil, date_eod = false) case time when DateTime warn "IceCube: DateTime support is deprecated (please use Time) at: #{caller(3..3).first}" Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec) when Date if date_eod end_of_date(time, reference) elsif reference build_in_zone([time.year, time.month, time.day], reference) else time.to_time end else time end end |
.hash(time) ⇒ Object
Get a more precise equality for time objects Ruby provides a Time#hash method, but it fails to account for UTC offset (so the current date may be different) or DST rules (so the hour may be wrong for different schedule occurrences)
120 121 122 |
# File 'lib/ice_cube/time_util.rb', line 120 def self.hash(time) [time, time.utc_offset, time.zone].hash end |
.ical_day_to_symbol(str) ⇒ Object
181 182 183 184 185 |
# File 'lib/ice_cube/time_util.rb', line 181 def self.ical_day_to_symbol(str) day = ICAL_DAYS[str] raise ArgumentError, "Invalid day: #{str}" if day.nil? day end |
.match_zone(input_time, reference) ⇒ Object
43 44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/ice_cube/time_util.rb', line 43 def self.match_zone(input_time, reference) return unless (time = ensure_time(input_time, reference)) time = if reference.respond_to? :time_zone time.in_time_zone(reference.time_zone) elsif reference.utc? time.getgm elsif reference.zone time.getlocal else time.getlocal(reference.utc_offset) end (Date === input_time) ? beginning_of_date(time, reference) : time end |
.normalize_wday(wday, week_start) ⇒ Object
Convert weekday from base sunday to the schedule’s week start.
176 177 178 |
# File 'lib/ice_cube/time_util.rb', line 176 def self.normalize_wday(wday, week_start) (wday - sym_to_wday(week_start)) % 7 end |
.now(reference = Time.now) ⇒ Object
Provides a Time.now without the usec, in the reference zone or utc offset
27 28 29 |
# File 'lib/ice_cube/time_util.rb', line 27 def self.now(reference = Time.now) match_zone(Time.at(Time.now.to_i), reference) end |
.restore_deserialized_offset(time, orig_offset_str) ⇒ Object
Check the deserialized time offset string against actual local time offset to try and preserve the original offset for plain Ruby Time. If the offset is the same as local we can assume the same original zone and keep it. If it was serialized with a different offset than local TZ it will lose the zone and not support DST.
129 130 131 132 133 134 |
# File 'lib/ice_cube/time_util.rb', line 129 def self.restore_deserialized_offset(time, orig_offset_str) return time if time.respond_to?(:time_zone) || time.getlocal(orig_offset_str).utc_offset == time.utc_offset warn "IceCube: parsed Time from nonlocal TZ. Use ActiveSupport to fix DST at: #{caller(1..1).first}" time.localtime(orig_offset_str) end |
.serialize_time(time) ⇒ Object
Serialize a time appropriate for storing
86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/ice_cube/time_util.rb', line 86 def self.serialize_time(time) case time when Time, Date if time.respond_to?(:time_zone) {time: time.utc, zone: time.time_zone.name} else time end when DateTime Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec) else raise ArgumentError, "cannot serialize #{time.inspect}, expected a Time" end end |
.subsec(time) ⇒ Object
Handle discrepancies between various time types
-
Time has subsec
-
DateTime does not
-
ActiveSupport::TimeWithZone can wrap either type, depending on version or if ‘parse` or `now`/`local` was used to build it.
256 257 258 259 260 261 262 263 264 |
# File 'lib/ice_cube/time_util.rb', line 256 def self.subsec(time) if time.respond_to?(:subsec) time.subsec elsif time.respond_to?(:sec_fraction) time.sec_fraction else 0.0 end end |
.sym_to_month(sym) ⇒ Object
Convert a symbol to a numeric month
147 148 149 150 151 152 153 |
# File 'lib/ice_cube/time_util.rb', line 147 def self.sym_to_month(sym) MONTHS.fetch(sym) do |k| MONTHS.values.detect { |i| i.to_s == k.to_s } or raise ArgumentError, "Expecting Integer or Symbol value for month. " \ "No such month: #{k.inspect}" end end |
.sym_to_wday(sym) ⇒ Object
Convert a symbol to a wday number
157 158 159 160 161 162 163 |
# File 'lib/ice_cube/time_util.rb', line 157 def self.sym_to_wday(sym) DAYS.fetch(sym) do |k| DAYS.values.detect { |i| i.to_s == k.to_s } or raise ArgumentError, "Expecting Integer or Symbol value for weekday. " \ "No such weekday: #{k.inspect}" end end |
.wday_to_sym(wday) ⇒ Object
Convert wday number to day symbol
167 168 169 170 171 172 173 |
# File 'lib/ice_cube/time_util.rb', line 167 def self.wday_to_sym(wday) return wday if DAYS.key? wday DAYS.invert.fetch(wday) do |i| raise ArgumentError, "Expecting Integer value for weekday. " \ "No such wday number: #{i.inspect}" end end |
.which_occurrence_in_month(time, wday) ⇒ Object
Return the count of the number of times wday appears in the month, and which of those time falls on
189 190 191 192 193 194 |
# File 'lib/ice_cube/time_util.rb', line 189 def self.which_occurrence_in_month(time, wday) first_occurrence = ((7 - Time.utc(time.year, time.month, 1).wday) + time.wday) % 7 + 1 this_weekday_in_month_count = ((days_in_month(time) - first_occurrence + 1) / 7.0).ceil nth_occurrence_of_weekday = (time.mday - first_occurrence) / 7 + 1 [nth_occurrence_of_weekday, this_weekday_in_month_count] end |