Reputation: 384
This snippet of code determines the date for the nth weekday of a given month.
Example: for the 2nd Tuesday of December 2013:
>> nth_weekday(2013,11,2,2)
=> Tue Nov 12 00:00:00 UTC 2013
Last Sunday of December 2013:
>> nth_weekday(2013,12,'last',0)
=> Sun Dec 29 00:00:00 UTC 2013
I was not able to find working code for this question so I'm sharing my own.
Upvotes: 3
Views: 1492
Reputation: 27855
You can use:
require 'date'
class Date
#~ class DateError < ArgumentError; end
#Get the third monday in march 2008: new_by_mday( 2008, 3, 1, 3)
#
#Based on http://forum.ruby-portal.de/viewtopic.php?f=1&t=6157
def self.new_by_mday(year, month, weekday, nr)
raise( ArgumentError, "No number for weekday/nr") unless weekday.respond_to?(:between?) and nr.respond_to?(:between?)
raise( ArgumentError, "Number not in Range 1..5: #{nr}") unless nr.between?(1,5)
raise( ArgumentError, "Weekday not between 0 (Sunday)and 6 (Saturday): #{nr}") unless weekday.between?(0,6)
day = (weekday-Date.new(year, month, 1).wday)%7 + (nr-1)*7 + 1
if nr == 5
lastday = (Date.new(year, (month)%12+1, 1)-1).day # each december has the same no. of days
raise "There are not 5 weekdays with number #{weekday} in month #{month}" if day > lastday
end
Date.new(year, month, day)
end
end
p Date.new_by_mday(2013,11,2,2)
This is also available in a gem:
gem "date_tools", "~> 0.1.0"
require 'date_tools/date_creator'
p Date.new_by_mday(2013,11,2,2)
Upvotes: 1
Reputation: 29124
If you are using Rails
, you can do this.
def nth_weekday(year, month, n, wday)
first_day = DateTime.new(year, month, 1)
arr = (first_day..(first_day.end_of_month)).to_a.select {|d| d.wday == wday }
n == 'last' ? arr.last : arr[n - 1]
end
> n = nth_weekday(2013,11,2,2)
# => Tue, 12 Nov 2013 00:00:00 +0000
Upvotes: 7
Reputation: 384
# nth can be 1..4 or 'last'
def nth_weekday(year,month,nth,week_day)
first_date = Time.gm(year,month,1)
last_date = month < 12 ? Time.gm(year,month+1)-1.day : Time.gm(year+1,1)-1.day
date = nil
if nth.class == Fixnum and nth > 0 and nth < 5
date = first_date
nth_counter = 0
while date <= last_date
nth_counter += 1 if date.wday == week_day
nth_counter == nth ? break : date += 1.day
end
elsif nth == 'last'
date = last_date
while date >= first_date
date.wday == week_day ? break : date -= 1.day
end
else
raise 'Error: nth_weekday called with out of range parameters'
end
return date
end
Upvotes: 0