Suprdate

Objects that represent dates (Year, Month and Day etc.) These are used for the purposes of traversal, iteration and arithmetic.

Installation

cd ~ # or wherever you want it installed
git clone git://github.com/olliesaunders/suprdate.git
cd suprdate
spec spec/* # check to see that it's working (requires rspec)
bin/irb # this script requires and includes the library, and starts an interactive ruby session

Inclusion

require PATH_TO_SUPRDATE + '/lib/suprdate'
include Suprdate

Features

>> y = Year(2008) # => 2008
>> y.leap? # => true
>> y += 1 # => 2009
>> y.leap? # => false
>> y.months.class # => Array
>> y.months[0..2] # => [2009-01, 2009-02, 2009-03]
>> y.since(Year(2000)) # => 9
>> y.month # => 2009-01
>> y.day # => 2009-01-01
>> y[2]   # => 2009-02
>> y[2, 3, :jun] # => [2009-02, 2009-03, 2009-06]
>> y.days[0..2] # => [2009-01-01, 2009-01-02, 2009-01-03]
>> y.days.nitems # => 365

>> m = Month(2008, 1) # => 2008-01
>> m += 2 # => 2008-03
>> m.to_s # => "2008-03"
>> m.to_sym # => :mar
>> m[1] # => 2008-03-01
>> m[1, 3] # => [2008-03-01, 2008-03-03]
>> m[1, 3, -1, -3] # => [2008-03-01, 2008-03-03, 2008-03-31, 2008-03-29]
>> m > Year(2008) # => true
>> m > Year(2009) # => false
>> m > Month(2008, 2) # => true
>> m > Month(2008, 3) # => false
>> m += 24 # => 2010-03

>> y.month # => 2009-01
>> d = y.day # => 2009-01-01
>> d = Day(2009, 1, 1) # 2009-01-01
>> d.until(d.month + 1) # => 31 # num days until the next month
>> d.since(d.month - 2) # => 61 # num days since two months ago
>> d.of_week_as_s # => "Thursday"
>> d.of_week_as_sym # => :thu
>> d.of_week_as_i  # => 5
>> d.date # => #<Date: 4909665/2,0,2299161>
>> d.date.strftime("%Y-%m-%d") # => "2009-01-01"
>> d.weekday_occurrence_this_month # => :first
>> (d + 7).weekday_occurrence_this_month # => :second
>> (d + 21).weekday_occurrence_this_month # => :fourth

>> Today() # => 2008-11-30
>> Date(2000) # => 2000
>> Date(2000, 10) # => 2000-10
>> Date(2000, 10, 1) # => 2000-10-01

You can also do things with ranges:

>> (Day(2008, 1, 1)..Day(2008, 1, 3)).to_a # => [2008-01-01, 2008-01-02, 2008-01-03]
>> (Month(2008, 1)..Day(2008, 3, 10)).to_a # => [2008-01, 2008-02, 2008-03]
>> (Year(2005)..Day(2009, 1, 3)).to_a # => [2005, 2006, 2007, 2008, 2009]

Note that the value you provide on the right side of the range is implicitly converted to the same type as one the left so that they can be enumerated. This means the type you use on the left of the range will determine the type of the output.

(Year(2005)..Infinity) creates a range that has no end. If you call #to_a on it ruby will go into an infinite loop. Call each on this to iterate until you wish to break.

Currently there are no week objects. It's on the TODO.

The lone-standing every method can be used to filter any list by a specified frequency:

>> every(3, Year(2008).months)
=> [2008-01, 2008-04, 2008-07, 2008-10]
>> every(:third, Year(2008).months)
=> [2008-01, 2008-04, 2008-07, 2008-10]

It will accept a block too if you are that way inclined. If a block is given every will return the original list unaltered.

Meta-Programming

Currently there is a single meta-programming technique in use in Suprdate

The methods beginning with an uppercase such as Year, Month and Day and Today are created dynamically at require time and actually each represent calls to DEFAULT_BUILDER:

>> Year(2008) == DEFAULT_BUILDER.year(2008) # => true
>> Year(2008) == Builder.new.year(2008) # => true

This is done to make the existence of a builder completely transparent to the developer. At present I can see no reason to interact with the builder, define you own builders or worry about this for any reason.