如何确定一个月的第n个工作日?

时间:2022-10-16 10:10:38

This snippet of code determines the date for the nth weekday of a given month.

这个代码片段确定了一个月的第n个工作日的日期。

Example: for the 2nd Tuesday of December 2013:

例子:2013年12月2日星期二:

>> nth_weekday(2013,11,2,2)
=> Tue Nov 12 00:00:00 UTC 2013

Last Sunday of December 2013:

2013年12月最后一个周日:

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

我找不到这个问题的工作代码,所以我在分享我自己的代码。

3 个解决方案

#1


4  

If you are using Rails, you can do this.

如果您正在使用Rails,您可以这样做。

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

#2


1  

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中找到:

gem "date_tools", "~> 0.1.0"
require 'date_tools/date_creator'
p Date.new_by_mday(2013,11,2,2)

#3


0  

# 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

#1


4  

If you are using Rails, you can do this.

如果您正在使用Rails,您可以这样做。

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

#2


1  

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中找到:

gem "date_tools", "~> 0.1.0"
require 'date_tools/date_creator'
p Date.new_by_mday(2013,11,2,2)

#3


0  

# 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