class XDate
def initialize(year, month, day)
@year, @month, @day = year.to_i, month.to_i, day.to_i
end
attr_reader :year, :month, :day
def to_s
format('%04d-%02d-%02d', @year, @month, @day)
end
alias :inspect :to_s
def to_time
Time.gm(@year, @month, @day)
end
def to_date
Date.new(@year, @month, @day)
end
def -(other)
case other
when XDate
(to_date - other.to_date)
when Time
to_time - other
when Date
(to_date - other.to_date)
else
to_date - other
end
end
def +(other)
t = to_date + other
self.class.new(t.year, t.month, t.mday)
end
end
class TimeNode < TerminalNode
def initialize(date, time, zone)
@date, @time, @zone = date, time, zone
if :now === @date then
now = Time.now.utc
@date = XDate.new(now.year, now.month, now.day)
@time = ((now.hour * 60 + now.min) * 60 + Float(now.sec))
else
qdays = (@time / 86400).floor
if not qdays.zero?
@date += qdays
@time -= (qdays * 86400)
end
end
raise TypeError unless XDate === @date
@time = 0.0 unless @time
raise TypeError unless Float === @time
@zone = 0 unless @zone
raise TypeError unless Integer === @zone
end
attr_reader :date, :time, :zone
def to_s
hr = @time.floor / 3600
mi = (@time.floor / 60) % 60
sc = @time % 60
tzm = @zone.abs
tzh = tzm / 60
tzm %= 60
tzh = -tzh if @zone < 0
format("%sT%02d:%02d:%05.2f %+03d:%02d", \
@date.to_s, hr, mi, sc, tzh, tzm)
end
def self::pentad(d)
(d > 25) ? 5 : ((d - 1) / 5)
end
def add_time(increment)
inc = increment.reduce5
case inc.name
when 's'
t2 = @time + inc.factor
d2 = @date + (t2 / 86400)
t2 = t2 % 86400
self.class.new(d2, t2, @zone)
when 'pentad'
ifac = Integer(inc.factor)
ipen = ifac % 6
imon = ifac / 6
spen = self.class.pentad(@date.day)
smon = @date.month + imon + spen / 6
spen = spen % 6
sday = spen * 5 + (@date.day - 1) % 5 + 1
syear = @date.year + (smon - 1) / 12
smon = (smon - 1) % 12 + 1
sdate = XDate.new(syear, smon, sday)
self.class.new(sdate, @time, @zone)
else
raise "bad time unit '#{inc.name}'"
end
end
def utcsod
@time - @zone * 60
end
def div_time(units)
base = units.ref
inc = units.deref.reduce5
begin
incname = inc.name
rescue Exception
incname = "(undefined)"
end
case incname
when 's'
dif = (@date - base.date) * 86400 + (utcsod - base.utcsod)
dif / inc.factor
when 'pentad'
dif = (@date.year - base.date.year) * 72
dif += (@date.month - base.date.month) * 6
dif += self.class.pentad(@date.day)
dif -= self.class.pentad(base.date.day)
dif = Float(dif) if dif % inc.factor != 0
dif / inc.factor
else
raise "bad time unit '#{incname}'"
end
end
end
syntax highlighted by Code2HTML, v. 0.9.1