我似乎无法找到一种优雅的方式来做到这一点......
给定一个日期,我怎样才能找到下一个星期二,即该日历月的第二个或第四个星期二?
例如:
给定2012-10-19
,然后返回2012-10-23
或
给定2012-10-31
,然后返回2012-11-13
October November
Su Mo Tu We Th Fr Sa Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 1 2 3
7 8 9 10 11 12 13 4 5 6 7 8 9 10
14 15 16 17 18 19 20 11 12 13 14 15 16 17
21 22 23 24 25 26 27 18 19 20 21 22 23 24
28 29 30 31 25 26 27 28 29 30
答案 0 :(得分:3)
如果您只想查看最终结果的样子,请滚动到底部..
使用我最近在ruby 1.9.3中完成的某些日期处理工作的代码片段。
DateTime
的一些升级:require 'date'
class DateTime
ALL_DAYS = [ 'sunday', 'monday', 'tuesday',
'wednesday', 'thursday', 'friday', 'saturday' ]
def next_week
self + (7 - self.wday)
end
def next_wday (n)
n > self.wday ? self + (n - self.wday) : self.next_week.next_day(n)
end
def nth_wday (n, i)
current = self.next_wday(n)
while (i > 0)
current = current.next_wday(n)
i = i - 1
end
current
end
def first_of_month
self - self.mday + 1
end
def last_of_month
self.first_of_month.next_month - 1
end
end
method_missing
技巧:我还补充了这个类,其中一些方法缺少技巧来映射从next_tuesday
到next_wday(2) and
nth_tuesday(2)to
nth_wday(2,2)`的调用,这使得下一个片段上的代码更容易。
class DateTime
# ...
def method_missing (sym, *args, &block)
day = sym.to_s.gsub(/^(next|nth)_(?<day>[a-zA-Z]+)$/i, '\k<day>')
dindex = ALL_DAYS.include?(day) ? ALL_DAYS.index(day.downcase) : nil
if (sym =~ /^next_[a-zA-Z]+$/i) && dindex
self.send(:next_wday, dindex)
elsif (sym =~ /^nth_[a-zA-Z]+$/i) && dindex
self.send(:nth_wday, dindex, args[0])
else
super(sym, *args, &block)
end
end
def respond_to? (sym)
day = sym.to_s.gsub(/^(next|nth)_(?<day>[a-zA-Z]+)$/i, '\k<day>')
(((sym =~ /^next_[a-zA-Z]+$/i) || (sym =~ /^nth_[a-zA-Z]+$/i)) && ALL_DAYS.include?(day)) || super(sym)
end
end
给定日期:
today = DateTime.now
second_tuesday = (today.first_of_month - 1).nth_tuesday(2)
fourth_tuesday = (today.first_of_month - 1).nth_tuesday(4)
if today == second_tuesday
puts "Today is the second tuesday of this month!"
elsif today == fourth_tuesday
puts "Today is the fourth tuesday of this month!"
else
puts "Today is not interesting."
end
您还可以修改method_missing
来处理:second_tuesday_of_this_month
,:fourth_tuesday_of_this_month
等来电。如果我决定在以后编写代码,我会在此处发布代码。< / p>
答案 1 :(得分:2)
答案 2 :(得分:1)
看看这个宝石,你或许可以找到答案
答案 3 :(得分:1)
由于您已经使用了Rails,因此您不需要包含,但这也适用于纯Ruby以供参考。
require 'rubygems'
require 'active_support/core_ext'
d = DateTime.parse('2012-10-19')
result = nil
valid_weeks = [d.beginning_of_month.cweek + 1, d.beginning_of_month.cweek + 3]
if valid_weeks.include?(d.next_week(:tuesday).cweek)
result = d.next_week(:tuesday)
else
result = d.next_week.next_week(:tuesday)
end
puts result
答案 4 :(得分:0)
我认为你应该使用一个库,如果你需要扩展到更有趣的逻辑,但如果你所描述的只是你需要的,下面的代码应该有帮助
SECONDS_PER_DAY = 60 * 60 * 24
def find_tuesday_datenight(now)
tuesdays = [*-31..62].map { |i| now + (SECONDS_PER_DAY * i) }
.select { |d| d.tuesday? }
.group_by { |d| d.month }
[tuesdays[now.month][1], tuesdays[now.month][-2], tuesdays[(now.month + 1) % 12][1]]
.find {|d| d.yday > now.yday }
end
循环上个月和下个月,抓住星期二,逐个月,取当月的第二个和第二个星期二(如果你真的想要第四个星期二,只需改变-2到3)和下个月的第二个星期二,然后在提供的日期之后选择第一个。
以下是一些测试,每月4个星期二,每月5个星期二,随机,以及您的示例:
[[2013, 5, 1], [2013, 12, 1], [2012, 10, 1], [2012, 10, 19], [2012, 10, 31]].each do |t|
puts "#{t} => #{find_tuesday_datenight(Time.new *t)}"
end
产生
[2013, 5, 1] => 2013-05-14 00:00:00 +0800
[2013, 12, 1] => 2013-12-10 00:00:00 +0800
[2012, 10, 1] => 2012-10-09 00:00:00 +0800
[2012, 10, 19] => 2012-10-23 00:00:00 +0800
[2012, 10, 31] => 2012-11-13 00:00:00 +0800
我确信它可以简化,我很想听到一些建议:)(太迟了太累了,甚至懒得弄清楚有效日期的实际范围应该是多少,即小于-31。 0.62)
答案 5 :(得分:0)
所以这里的代码将解决一个月内某个特定星期的工作日(你要求的糖含量很少)。如果您在rails框架内运行,那么您应该没有问题。否则,请确保已安装active_support gem。方法名称是愚蠢的,所以随意改变它:)
用法:get_next_day_of_week(some_date, :friday, 1)
require 'rubygems'
require 'active_support/core_ext'
def get_next_day_of_week(date, day_name, count)
next_date = date + (-date.days_to_week_start(day_name.to_sym) % 7)
while (next_date.mday / 7) != count - 1 do
next_date = next_date + 7
end
next_date
end
答案 6 :(得分:0)
我使用以下内容计算Microsoft的补丁周二日期。它改编自一些C#代码。
require 'date'
#find nth iteration of given day (day specified in 'weekday' variable)
findnthday = 2
#Ruby wday number (days are numbered 0-7 beginning with Sunday)
weekday = 2
today = Time.now
todayM = today.month
todayY = today.year
StrtMonth = DateTime.new(todayY,todayM ,1)
while StrtMonth.wday != weekday do
StrtMonth = StrtMonth + 1;
end
PatchTuesday = StrtMonth + (7 * (findnthday - 1))