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.
- .same_clock?(t1, t2) ⇒ Boolean
-
.serialize_time(time) ⇒ Object
Serialize a time appropriate for storing.
-
.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.
-
.week_start(sym) ⇒ Object
Convert a symbol to an ical day (SU, MO).
-
.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
133 134 135 |
# File 'lib/ice_cube/time_util.rb', line 133 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
32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/ice_cube/time_util.rb', line 32 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)
221 222 223 224 225 226 227 |
# File 'lib/ice_cube/time_util.rb', line 221 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
200 201 202 203 |
# File 'lib/ice_cube/time_util.rb', line 200 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
242 243 244 245 |
# File 'lib/ice_cube/time_util.rb', line 242 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
236 237 238 239 |
# File 'lib/ice_cube/time_util.rb', line 236 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
206 207 208 209 |
# File 'lib/ice_cube/time_util.rb', line 206 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
230 231 232 233 |
# File 'lib/ice_cube/time_util.rb', line 230 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
213 214 215 216 |
# File 'lib/ice_cube/time_util.rb', line 213 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
100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/ice_cube/time_util.rb', line 100 def self.deserialize_time(time_or_hash) case time_or_hash when Time time_or_hash 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
247 248 249 250 251 252 |
# File 'lib/ice_cube/time_util.rb', line 247 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
138 139 140 |
# File 'lib/ice_cube/time_util.rb', line 138 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
82 83 84 85 86 87 88 |
# File 'lib/ice_cube/time_util.rb', line 82 def self.ensure_date(date) case date when Date then date else return 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
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/ice_cube/time_util.rb', line 61 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[2] }" Time.local(time.year, time.month, time.day, time.hour, time.min, time.sec) when Date if date_eod end_of_date(time, reference) else if reference build_in_zone([time.year, time.month, time.day], reference) else time.to_time end 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)
116 117 118 |
# File 'lib/ice_cube/time_util.rb', line 116 def self.hash(time) [time, time.utc_offset, time.zone].hash end |
.ical_day_to_symbol(str) ⇒ Object
184 185 186 187 188 |
# File 'lib/ice_cube/time_util.rb', line 184 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
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
# File 'lib/ice_cube/time_util.rb', line 44 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) else if reference.utc? time.utc elsif reference.zone time.getlocal else time.getlocal(reference.utc_offset) end 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.
179 180 181 |
# File 'lib/ice_cube/time_util.rb', line 179 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
28 29 30 |
# File 'lib/ice_cube/time_util.rb', line 28 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.
125 126 127 128 129 130 |
# File 'lib/ice_cube/time_util.rb', line 125 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[0] }" time.localtime(orig_offset_str) end |
.same_clock?(t1, t2) ⇒ Boolean
254 255 256 |
# File 'lib/ice_cube/time_util.rb', line 254 def self.same_clock?(t1, t2) CLOCK_VALUES.all? { |i| t1.send(i) == t2.send(i) } end |
.serialize_time(time) ⇒ Object
Serialize a time appropriate for storing
91 92 93 94 95 96 97 |
# File 'lib/ice_cube/time_util.rb', line 91 def self.serialize_time(time) if time.respond_to?(:time_zone) {:time => time.utc, :zone => time.time_zone.name} elsif time.is_a?(Time) time end end |
.sym_to_month(sym) ⇒ Object
Convert a symbol to a numeric month
143 144 145 146 147 148 149 |
# File 'lib/ice_cube/time_util.rb', line 143 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
153 154 155 156 157 158 159 |
# File 'lib/ice_cube/time_util.rb', line 153 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
163 164 165 166 167 168 169 |
# File 'lib/ice_cube/time_util.rb', line 163 def self.wday_to_sym(wday) return sym = wday if DAYS.keys.include? wday DAYS.invert.fetch(wday) do |i| raise ArgumentError, "Expecting Integer value for weekday. " \ "No such wday number: #{i.inspect}" end end |
.week_start(sym) ⇒ Object
Convert a symbol to an ical day (SU, MO)
172 173 174 175 176 |
# File 'lib/ice_cube/time_util.rb', line 172 def self.week_start(sym) raise ArgumentError, "Invalid day: #{str}" unless DAYS.keys.include?(sym) day = sym.to_s.upcase[0..1] day 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
192 193 194 195 196 197 |
# File 'lib/ice_cube/time_util.rb', line 192 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 |