1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 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 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159
|
module Chronic
class RepeaterTime < Repeater #:nodoc:
class Tick #:nodoc:
attr_accessor :time
def initialize(time, ambiguous = false)
@time = time
@ambiguous = ambiguous
end
def ambiguous?
@ambiguous
end
def *(other)
Tick.new(@time * other, @ambiguous)
end
def to_f
@time.to_f
end
def to_s
@time.to_s + (@ambiguous ? '?' : '')
end
end
def initialize(time, options = {})
@current_time = nil
@options = options
time_parts = time.split(':')
raise ArgumentError, "Time cannot have more than 4 groups of ':'" if time_parts.count > 4
if time_parts.first.length > 2 and time_parts.count == 1
if time_parts.first.length > 4
second_index = time_parts.first.length - 2
time_parts.insert(1, time_parts.first[second_index..time_parts.first.length])
time_parts[0] = time_parts.first[0..second_index - 1]
end
minute_index = time_parts.first.length - 2
time_parts.insert(1, time_parts.first[minute_index..time_parts.first.length])
time_parts[0] = time_parts.first[0..minute_index - 1]
end
ambiguous = false
hours = time_parts.first.to_i
if @options[:hours24].nil? or (not @options[:hours24].nil? and @options[:hours24] != true)
ambiguous = true if (time_parts.first.length == 1 and hours > 0) or (hours >= 10 and hours <= 12) or (@options[:hours24] == false and hours > 0)
hours = 0 if hours == 12 and ambiguous
end
hours *= 60 * 60
minutes = 0
seconds = 0
subseconds = 0
minutes = time_parts[1].to_i * 60 if time_parts.count > 1
seconds = time_parts[2].to_i if time_parts.count > 2
subseconds = time_parts[3].to_f / (10 ** time_parts[3].length) if time_parts.count > 3
@type = Tick.new(hours + minutes + seconds + subseconds, ambiguous)
end
# Return the next past or future Span for the time that this Repeater represents
# pointer - Symbol representing which temporal direction to fetch the next day
# must be either :past or :future
def next(pointer)
super
half_day = 60 * 60 * 12
full_day = 60 * 60 * 24
first = false
unless @current_time
first = true
midnight = Chronic.time_class.local(@now.year, @now.month, @now.day)
yesterday_midnight = midnight - full_day
tomorrow_midnight = midnight + full_day
catch :done do
if pointer == :future
if @type.ambiguous?
[midnight, midnight + half_day, tomorrow_midnight].each do |base_time|
t = adjust_daylight_savings_offset(midnight, base_time + @type.time)
(@current_time = t; throw :done) if t >= @now
end
else
[midnight, tomorrow_midnight].each do |base_time|
t = adjust_daylight_savings_offset(midnight, base_time + @type.time)
(@current_time = t; throw :done) if t >= @now
end
end
else # pointer == :past
if @type.ambiguous?
[midnight + half_day, midnight, yesterday_midnight + half_day].each do |base_time|
t = adjust_daylight_savings_offset(midnight, base_time + @type.time)
(@current_time = t; throw :done) if t <= @now
end
else
[midnight, yesterday_midnight].each do |base_time|
t = adjust_daylight_savings_offset(midnight, base_time + @type.time)
(@current_time = t; throw :done) if t <= @now
end
end
end
end
@current_time || raise("Current time cannot be nil at this point")
end
unless first
increment = @type.ambiguous? ? half_day : full_day
@current_time += pointer == :future ? increment : -increment
end
Span.new(@current_time, @current_time + width)
end
# Every time a time crosses a Daylight Savings interval we must adjust the
# current time by that amount. For example, if we take midnight of Daylight
# Savings and only add an hour, the offset does not change:
#
# Time.parse('2008-03-09 00:00')
# => 2008-03-09 00:00:00 -0800
# Time.parse('2008-03-09 00:00') + (60 * 60)
# => 2008-03-09 01:00:00 -0800
#
# However, if we add 2 hours, we notice the time advances to 03:00 instead of 02:00:
#
# Time.parse('2008-03-09 00:00') + (60 * 60 * 2)
# => 2008-03-09 03:00:00 -0700
#
# Since we gained an hour and we actually want 02:00, we subtract an hour.
def adjust_daylight_savings_offset(base_time, current_time)
offset_fix = base_time.gmt_offset - current_time.gmt_offset
current_time + offset_fix
end
def this(context = :future)
super
context = :future if context == :none
self.next(context)
end
def width
1
end
def to_s
super << '-time-' << @type.to_s
end
end
end
|