Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 10dc43289c
Fetching contributors…

Cannot retrieve contributors at this time

102 lines (83 sloc) 3.829 kB
class Date
def next_(weekday, after = 1)
# returns today + 7 if today is also the same weekday
# this is to prevent us getting stuck in an endless loop
# the :after parameter allows us to get the nth such weekday
n = self - self.wday + WEEKDAYS.index(weekday) + 1
after += 1 if n <= self
return n + (7 * (after - 1))
end
def first_day_of_month
self - self.day + 1
end
def last_day_of_month
Date.new(self.month == 12 ? self.year + 1 : self.year, self.month == 12 ? 1 : self.month + 1, 1) - 1
end
end
class DateVector
# This class returns a string of dates given a periodicity
# every <nth>, <mth> <weekday> of every <oth> week i.e. every Thursday, every second Tuesday
# every <nth>, <mth>.... date of every <oth> month i.e. 12 and 29th of every month, 2nd of every other month
# every <nth>, <mth> <weekday> of the month i.e. 2nd and 4th Friday
# this class does not check correctness of inputs.
# Rather it borks spectacularly on bad input because failing silently or returning empty arrays is MUCH WORSE than raising exceptions
# ALL begin rescue end to be handled by calling party.
attr_accessor :every, :what, :of_every, :period, :from, :to, :dates
def initialize(every, what, of_every, period, from, to)
# i.e. DateVector.new(1, [:tuesday, :thursday], 2, :week, d1, d2) => every second tuesday and thursday
# ([2,4],[:tuesday, :thursday],2,:month, d1, d2) => every second and fourth tuesday and thursday of every second month
@every = every
@what = what
@of_every = of_every
@period = period
@from = from
@to = to
end
def get_next_n_dates(n, from = Date.today, override_to_date = false)
# gets the next n dates from from date. Stops at @to unless you override_to_date
ds = get_dates(from, n)
override_to_date ? ds.select{|d| d <= @to} : ds
end
def get_dates(from = @from, to = @to)
# get the dates as specified by this vector from the from date uptil "to" if "to" is a Date, or else get "to" such dates if an integer
raise ArgumentError.new("from must be a date") unless from.class == Date
raise ArgumentError.new("to must be either a date or an Integer") unless (to.class == Date or to.class == Fixnum)
d = @from; rv = []; i = 0
case @period
when :week
while (to.class == Date ? d <= to : i <= to)
[@what].flatten.map do |wday| # convert :tuesday into [:tuesday] so we can treat everything as an array
d = d.next_(wday)
rv << d if ((to.class == Date ? d <= to : i <= to) and d >= from)
d = d + ((@of_every - 1) * 7)
i = rv.count - 1
end
end
when :month
if @what == :day
# handle dates i.e. every => [15,22], what => :day, :of_every => 1, :period => :month means the 15th and 22nd of every month
while (to.class == Date ? d<= to : i <= to)
[@every].flatten.each do |e|
d = d.first_day_of_month + e.to_i - 1
rv << d if d >= from and (to.class == Date ? d <= to : i <= to)
end
d = (d.last_day_of_month + 1) >> (@of_every - 1)
i += 1
end
else
# handle 2nd tuesday every 2nd month type. every = 2, what = :tuesday, :of_every = 2, :period = :month
while (to.class == Date ? d <= to : i <= to)
[@every].flatten.each do |e|
[@what].flatten.each do |w|
d = d.first_day_of_month.next_(w,e.to_i)
rv << d if d >= from and (to.class == Date ? d <= to : i <= to)
end
end
d = (d.last_day_of_month + 1) >> (@of_every - 1)
i += 1
end
end
end
@dates = rv.select{|d| d >= from and (to.class == Date ? d <= to : true)}
end
end
Jump to Line
Something went wrong with that request. Please try again.