module IceCube::TimeUtil
Constants
- CLOCK_VALUES
- DAYS
- ICAL_DAYS
- MONTHS
Public Class Methods
Get the beginning of a date
# File lib/ice_cube/time_util.rb, line 117 def self.beginning_of_date(date, reference=Time.now) build_in_zone([date.year, date.month, date.day, 0, 0, 0], reference) end
# 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
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)
# File lib/ice_cube/time_util.rb, line 205 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
Get the days in the month for +time
# File lib/ice_cube/time_util.rb, line 184 def self.days_in_month(time) date = Date.new(time.year, time.month, 1) ((date >> 1) - date).to_i end
The number of days in n months
# File lib/ice_cube/time_util.rb, line 226 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
Number of days to n years
# File lib/ice_cube/time_util.rb, line 220 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
Get the days in the following month for +time
# File lib/ice_cube/time_util.rb, line 190 def self.days_in_next_month(time) date = Date.new(time.year, time.month, 1) >> 1 ((date >> 1) - date).to_i end
Number of days in a year
# File lib/ice_cube/time_util.rb, line 214 def self.days_in_year(time) date = Date.new(time.year, 1, 1) ((date >> 12) - date).to_i end
Count the number of days to the same day of the next month without overflowing shorter months
# File lib/ice_cube/time_util.rb, line 197 def self.days_to_next_month(time) date = Date.new(time.year, time.month, time.day) ((date >> 1) - date).to_i end
Deserialize a time serialized with ::serialize_time or in ISO8601 string format
# File lib/ice_cube/time_util.rb, line 92 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
# File lib/ice_cube/time_util.rb, line 231 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
Get the end of a date
# File lib/ice_cube/time_util.rb, line 122 def self.end_of_date(date, reference=Time.now) build_in_zone([date.year, date.month, date.day, 23, 59, 59], reference) end
Ensure that this is either nil, or a date
# File lib/ice_cube/time_util.rb, line 74 def self.ensure_date(date) case date when Date then date else return Date.new(date.year, date.month, date.day) end end
Ensure that this is either nil, or a time
# File lib/ice_cube/time_util.rb, line 61 def self.ensure_time(time, 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 date_eod ? end_of_date(time) : time.to_time else time end end
# File lib/ice_cube/time_util.rb, line 168 def self.ical_day_to_symbol(str) day = ICAL_DAYS[str] raise ArgumentError, "Invalid day: #{str}" if day.nil? day end
# File lib/ice_cube/time_util.rb, line 44 def self.match_zone(input_time, reference) return unless time = ensure_time(input_time) 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
Convert weekday from base sunday to the schedule's week start.
# File lib/ice_cube/time_util.rb, line 163 def self.normalize_wday(wday, week_start) (wday - sym_to_wday(week_start)) % 7 end
Provides a Time.now without the usec, in the reference zone or utc offset
# 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
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.
# File lib/ice_cube/time_util.rb, line 109 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
# File lib/ice_cube/time_util.rb, line 238 def self.same_clock?(t1, t2) CLOCK_VALUES.all? { |i| t1.send(i) == t2.send(i) } end
Serialize a time appropriate for storing
# File lib/ice_cube/time_util.rb, line 83 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
Convert a symbol to a numeric month
# File lib/ice_cube/time_util.rb, line 127 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 Fixnum or Symbol value for month. " "No such month: #{k.inspect}" end end
Convert a symbol to a wday number
# File lib/ice_cube/time_util.rb, line 137 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 Fixnum or Symbol value for weekday. " "No such weekday: #{k.inspect}" end end
Convert wday number to day symbol
# File lib/ice_cube/time_util.rb, line 147 def self.wday_to_sym(wday) return sym = wday if DAYS.keys.include? wday DAYS.invert.fetch(wday) do |i| raise ArgumentError, "Expecting Fixnum value for weekday. " "No such wday number: #{i.inspect}" end end
Convert a symbol to an ical day (SU, MO)
# File lib/ice_cube/time_util.rb, line 156 def self.week_start(sym) raise ArgumentError, "Invalid day: #{str}" unless DAYS.keys.include?(sym) day = sym.to_s.upcase[0..1] day end
Return the count of the number of times wday appears in the month, and which of those time falls on
# File lib/ice_cube/time_util.rb, line 176 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