module IceCube::TimeUtil

Constants

CLOCK_VALUES
DAYS
ICAL_DAYS
MONTHS

Public Class Methods

beginning_of_date(date, reference=Time.now) click to toggle source

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
build_in_zone(args, reference) click to toggle source
# 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) click to toggle source

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
days_in_month(time) click to toggle source

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
days_in_n_months(time, month_distance) click to toggle source

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
days_in_n_years(time, year_distance) click to toggle source

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
days_in_next_month(time) click to toggle source

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
days_in_year(time) click to toggle source

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
days_to_next_month(time) click to toggle source

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_time(time_or_hash) click to toggle source

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
dst_change(time) click to toggle source
# 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
end_of_date(date, reference=Time.now) click to toggle source

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_date(date) click to toggle source

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_time(time, date_eod = false) click to toggle source

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
ical_day_to_symbol(str) click to toggle source
# 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
match_zone(input_time, reference) click to toggle source
# 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
normalize_wday(wday, week_start) click to toggle source

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
now(reference=Time.now) click to toggle source

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
restore_deserialized_offset(time, orig_offset_str) click to toggle source

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
same_clock?(t1, t2) click to toggle source
# 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_time(time) click to toggle source

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
sym_to_month(sym) click to toggle source

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
sym_to_wday(sym) click to toggle source

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
wday_to_sym(wday) click to toggle source

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
week_start(sym) click to toggle source

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
which_occurrence_in_month(time, wday) click to toggle source

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