In Files

Parent

Date

Extensions to the standard library Date.

Public Class Methods

bywday(year, mon, wday, n = 1, sg=Date::ITALY) click to toggle source

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.

# File lib/vpim/date.rb, line 84
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) click to toggle source

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.
# File lib/vpim/date.rb, line 45
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") click to toggle source

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).

# File lib/vpim/date.rb, line 128
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

Public Instance Methods

vpim_to_time() click to toggle source

Converts this object to a Time object, or throws an ArgumentError if conversion is not possible because it is before the start of epoch.

# File lib/vpim/date.rb, line 20
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

[Validate]

Generated with the Darkfish Rdoc Generator 2.