Class: Date
- Inherits:
-
Object
- Object
- Date
- Defined in:
- lib/vpim/date.rb
Overview
Extensions to the standard library Date.
Constant Summary collapse
- TIME_START =
Date.new(1970, 1, 1)
- SECS_PER_DAY =
24 * 60 * 60
Class Method Summary collapse
-
.bywday(year, mon, wday, n = 1, sg = Date::ITALY) ⇒ Object
Create a new Date object for the date specified by year
year
, monthmon
, and day-of-the-weekwday
. -
.str2wday(wdaystr) ⇒ Object
If wday responds to to_str, convert it to the wday number by searching for a wday that matches, using as many characters as are in wday to do the comparison.
-
.weekstart(year, mon, day, weekstart = "MO") ⇒ Object
Return the first day of the week for the specified date.
Instance Method Summary collapse
-
#vpim_to_time ⇒ Object
Converts this object to a Time object, or throws an ArgumentError if conversion is not possible because it is before the start of epoch.
Class Method Details
.bywday(year, mon, wday, n = 1, sg = Date::ITALY) ⇒ Object
Create a new Date object for the date specified by year year
, month mon
, and day-of-the-week wday
.
The nth, n
, occurrence of wday
within the period will be generated (n
defaults to 1). If n
is positive, the nth occurrence from the beginning of the period will be returned, if negative, the nth occurrence from the end of the period will be returned.
The period is a year, unless month
is non-nil, in which case it is just that month.
Examples:
-
Date.bywday(2004, nil, 1, 9) => the ninth Sunday of 2004
-
Date.bywday(2004, nil, 1) => the first Sunday of 2004
-
Date.bywday(2004, nil, 1, -2) => the second last Sunday of 2004
-
Date.bywday(2004, 12, 1) => the first sunday in the 12th month of 2004
-
Date.bywday(2004, 2, 2, -1) => last Tuesday in the 2nd month in 2004
-
Date.bywday(2004, -2, 3, -2) => second last Wednesday in the second last month of 2004
Compare this to Date.new, which allows a Date to be created by day-of-the-month, mday, to Date.ordinal, which allows a Date to be created by day-of-the-year, yday, and to Date.commercial, which allows a Date to be created by day-of-the-week, but within a specific week.
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 |
# File 'lib/vpim/date.rb', line 83 def Date.bywday(year, mon, wday, n = 1, sg=Date::ITALY) # Normalize mon to 1-12. if mon if mon > 12 || mon == 0 || mon < -12 raise ArgumentError, "mon #{mon} must be 1-12 or negative 1-12" end if mon < 0 mon = 13 + mon end end if wday < 0 || wday > 6 raise ArgumentError, 'wday must be in range 0-6, or a weekday name' end # Determine direction of indexing. inc = n <=> 0 if inc == 0 raise ArgumentError, 'n must be greater or less than zero' end # if !mon, n is index into year, but direction of search is determined by # sign of n d = Date.new(year, mon ? mon : inc, inc, sg) while d.wday != wday d += inc end # Now we have found the first/last day with the correct wday, search # for nth occurrence, by jumping by n.abs-1 weeks forward or backward. d += 7 * (n.abs - 1) * inc if d.year != year raise ArgumentError, 'n is out of bounds of year' end if mon && d.mon != mon raise ArgumentError, 'n is out of bounds of month' end d end |
.str2wday(wdaystr) ⇒ Object
If wday responds to to_str, convert it to the wday number by searching for a wday that matches, using as many characters as are in wday to do the comparison. wday must be 2 or more characters long in order to be a unique match, other than that, “mo”, “Mon”, and “MonDay” are all valid strings for wday 1.
This method can be called on a valid wday, and it will return it. Perhaps it should be called by default inside the Date#new*() methods so that non-integer wday arguments can be used? Perhaps a similar method should exist for months? But with months, we all know January is 1, who can remember where Date chooses to start its wday count!
Examples:
Date.bywday(2004, 2, Date.str2wday('TU')) => the first Tuesday in
February
Date.bywday(2004, 2, Date.str2wday(2)) => the same day, but notice
that a valid wday integer can be passed right through.
44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# File 'lib/vpim/date.rb', line 44 def Date.str2wday(wdaystr) return wdaystr unless wdaystr.respond_to? :to_str str = wdaystr.to_str.upcase if str.length < 2 raise ArgumentError, 'wday #{wday} is not long enough to be a unique weekday name' end wday = Date::DAYNAMES.map { |n| n.slice(0, str.length).upcase }.index(str) return wday if wday raise ArgumentError, 'wday #{wdaystr} was not a recognizable weekday name' end |
.weekstart(year, mon, day, weekstart = "MO") ⇒ Object
Return the first day of the week for the specified date. Commercial weeks start on Monday, but the weekstart can be specified (as 0-6, where 0 is sunday, or in formate of Date.str2day).
127 128 129 130 131 132 133 134 |
# File 'lib/vpim/date.rb', line 127 def Date.weekstart(year, mon, day, weekstart="MO") wkst = Date.str2wday(weekstart) d = Date.new(year, mon, day) until d.wday == wkst d = d - 1 end d end |
Instance Method Details
#vpim_to_time ⇒ Object
Converts this object to a Time object, or throws an ArgumentError if conversion is not possible because it is before the start of epoch.
19 20 21 22 23 24 |
# File 'lib/vpim/date.rb', line 19 def vpim_to_time raise ArgumentError, 'date is before the start of system time' if self < TIME_START days = self - TIME_START Time.at((days * SECS_PER_DAY).to_i) end |