Module: IceCube::TimeUtil

Included in:
IceCube
Defined in:
lib/ice_cube/time_util.rb

Constant Summary collapse

LeapYearMonthDays =
[31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
CommonYearMonthDays =
[31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]

Class Method Summary collapse

Class Method Details

.adjust(goal, date) ⇒ Object



58
59
60
61
# File 'lib/ice_cube/time_util.rb', line 58

def self.adjust(goal, date)
  return goal if goal.utc_offset == date.utc_offset
  goal - goal.utc_offset + date.utc_offset
end

.date_in_n_months(date, month_distance) ⇒ Object

TODO can we improve this more?



24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
# File 'lib/ice_cube/time_util.rb', line 24

def self.date_in_n_months(date, month_distance)
  
  next_mark = date
  days_in_month_of_next_mark = days_in_month(next_mark)
  
  month_distance.times do
    
    prev_mark = next_mark
    next_mark += days_in_month_of_next_mark * IceCube::ONE_DAY
    
    # only moving one day at a time, so this suffices
    months_covered = next_mark.month - prev_mark.month
    months_covered += 12 if months_covered < 0
    
    # step back to the end of the previous month of months_covered went too far
    if months_covered == 2
      next_mark -= next_mark.mday * IceCube::ONE_DAY
    end
    
    days_in_month_of_next_mark = days_in_month(next_mark)
    next_mark = adjust(next_mark, prev_mark)
    
  end
  
  # at the end, there's a chance we're not on the correct day,
  # but if we're not - we will always be behind it in the correct month
  # if there exists no proper day in the month for us, return nil - otherwise, return that date
  
  if days_in_month_of_next_mark >= date.mday
    next_mark += (date.mday - next_mark.mday) * IceCube::ONE_DAY
  end
  
end

.days_in_month(date) ⇒ Object



71
72
73
# File 'lib/ice_cube/time_util.rb', line 71

def self.days_in_month(date)
  is_leap?(date.year) ? LeapYearMonthDays[date.month - 1] : CommonYearMonthDays[date.month - 1]
end

.days_in_year(date) ⇒ Object



67
68
69
# File 'lib/ice_cube/time_util.rb', line 67

def self.days_in_year(date)
  is_leap?(date.year) ? 366 : 365
end

.deserialize_time(time_or_hash) ⇒ Object



16
17
18
19
20
21
# File 'lib/ice_cube/time_util.rb', line 16

def self.deserialize_time(time_or_hash) 
  return time_or_hash if time_or_hash.is_a?(Time) # for backward-compat
  if time_or_hash.is_a?(Hash)
    time_or_hash[:time].in_time_zone(time_or_hash[:zone])
  end
end

.ical_duration(duration) ⇒ Object



89
90
91
92
93
94
95
96
97
# File 'lib/ice_cube/time_util.rb', line 89

def self.ical_duration(duration)
  hours = duration / 3600; duration %= 3600
  minutes = duration / 60; duration %= 60
  repr = ''
  repr << "#{hours}H" if hours > 0
  repr << "#{minutes}M" if minutes > 0
  repr << "#{duration}S" if duration > 0
  "PT#{repr}"
end

.ical_format(time, force_utc) ⇒ Object



80
81
82
83
84
85
86
87
# File 'lib/ice_cube/time_util.rb', line 80

def self.ical_format(time, force_utc)
  time = time.dup.utc if force_utc
  if time.utc?
    ":#{time.strftime('%Y%m%dT%H%M%SZ')}" # utc time
  else
    ";TZID=#{time.strftime('%Z:%Y%m%dT%H%M%S')}" # local time specified
  end
end

.ical_utc_format(time) ⇒ Object



75
76
77
78
# File 'lib/ice_cube/time_util.rb', line 75

def self.ical_utc_format(time)
  time = time.dup.utc
  "#{time.strftime('%Y%m%dT%H%M%SZ')}" # utc time
end

.is_leap?(year) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
# File 'lib/ice_cube/time_util.rb', line 63

def self.is_leap?(year)
  (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)
end

.serialize_time(time) ⇒ Object



8
9
10
11
12
13
14
# File 'lib/ice_cube/time_util.rb', line 8

def self.serialize_time(time)
  if time.is_a?(ActiveSupport::TimeWithZone)
    { :time => time, :zone => time.time_zone.name }
  elsif time.is_a?(Time)
    time
  end
end