使用Ruby查找每月的特定日期

时间:2017-07-01 14:39:34

标签: ruby

我试图将日历系统构建到我的应用程序中。我目前所处的问题是每月一次。基本上,如果一个人在该月的第二个星期三安排,我想自动将时间表更新到下个月的第二个星期三。我尝试过添加+ 1.month,但这并没有达到我想要的效果。因为它将它移动到下个月的日期而不是一周中的某一天。有谁知道我怎么能做到这一点。以下是我目前正在做的事情,这是不对的。

def call
    schedule.update!(
      end_at: end_at_next_month,
      start_at: start_at_next_month,
      status: "monthly",
      arranged: true
    )
  end

  private

  def schedule
    context.schedule
  end

  def end_at_next_month
    schedule.end_at + 1.month
  end

  def start_at_next_month
    schedule.start_at + 1.month
  end
end

3 个答案:

答案 0 :(得分:2)

require 'date'

def date_of_nth_wday(month, year, wday, nth)
  base_date = Date.new(year, month)
  base_wday = base_date.wday
  ret_date = base_date +
             ( wday > base_wday ? wday - base_wday : 7 - base_wday + wday) +
             7*(nth-1)
  ret_date.month == month ? ret_date : nil
end

获取2017年8月第二个星期日的日期

date_of_nth_wday(8, 2017, 0, 2)
  #=> #<Date: 2017-08-13 ((2457979j,0s,0n),+0s,2299161j)>

获取2017年8月第三个星期五的日期

date_of_nth_wday(8, 2017, 5, 3)
  #=> #<Date: 2017-08-18 ((2457984j,0s,0n),+0s,2299161j)>

获取2017年8月第五个星期一的日期

date_of_nth_wday(8, 2017, 1, 5)
  #=> nil (there are only 4 Mondays in August, 2017)

答案 1 :(得分:1)

您可以尝试这样的事情:

DAYS_MAPPING = { 0=>"Sunday",
  1=>"Monday",
  2=>"Tuesday",
  3=>"Wednesday",
  4=>"Thursday",
  5=>"Friday",
  6=>"Saturday" }


# Returns week of month in integer
#   for example: 1 for matching day of 1st week of the month
def get_week_number(date)
  week_number = date.strftime('%U').to_i - date.beginning_of_month.strftime('%U').to_i
  offset = (Date.parse(DAYS_MAPPING[date.wday]) < date.beginning_of_month) ? 0 : 1

  week_number + offset
end

def specific_day_of_next_month(schedule)
  # wday => day of week in integer
  #   for example: 0 for Sunday; 1 for Monday & so on ...
  wday = schedule.wday
  week_number = get_week_number(schedule)

  next_month = schedule + 1.month
  days = (next_month.beginning_of_month..next_month.end_of_month).select { |d| d.wday == wday }
  days[week_number-1]
end

示例1:

schedule = Date.today
# => Sat, 01 Jul 2017 (First Saturday of July)

specific_day_of_next_month(schedule)
# => Sat, 05 Aug 2017 (First Saturday of August)

示例2:

schedule = Date.new(2017, 7, 10)
# => Mon, 10 Jul 2017 (Second Monday of July)

specific_day_of_next_month(schedule)
# => Mon, 14 Aug 2017 (Second Monday of August)

答案 2 :(得分:0)

您的标题与文中的说明不同。以我的例子你没有得到上周五,但你可以选择一个月的1,2,3,4,5周三(或任何其他日子)。

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

#2nd monday (weekday 1) in july
p Date.new_by_mday(2017,7,1,2)

如果你寻找宝石:date_tools支持这个功能。