[英]Ruby: given a date find the next 2nd or 4th Tuesday
I can't seem to find an elegant way to do this... 我似乎无法找到一种优雅的方式来做到这一点......
Given a date how can I find the next Tuesday that is either the 2nd or the 4th Tuesday of the calendar month? 在给定日期的情况下,如何找到下一个星期二,即该日历月的第二个或第四个星期二?
For example: 例如:
Given 2012-10-19
then return 2012-10-23
鉴于
2012-10-19
然后返回2012-10-23
or 要么
Given 2012-10-31
then return 2012-11-13
鉴于
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
Scroll to the bottom if you just want to see what the end result can look like.. 如果您只想查看最终结果的样子,请滚动到底部。
Using code snippets from some date processing work I've done recently in ruby 1.9.3. 使用我最近在ruby 1.9.3中完成的一些日期处理工作的代码片段。
DateTime
: 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
Tricks: method_missing
技巧: I have also supplemented the class with some method missing tricks to map calls from next_tuesday
to next_wday(2) and
nth_tuesday(2) to
nth_wday(2, 2)`, which makes the next snippet easier on the eyes. 我还补充了一些方法,用一些缺少技巧的方法来映射从
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
Given a date: 给定日期:
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
You could also edit method_missing
to handle calls such as :second_tuesday_of_this_month
, :fourth_tuesday_of_this_month
, etc. I'll post the code here if I decide to write it at a later date. 您还可以编辑
method_missing
来处理调用,例如:second_tuesday_of_this_month
, :fourth_tuesday_of_this_month
等。如果我决定在以后编写代码,我会在此处发布代码。
Check out this gem, you might be able to figure out your answer 看看这个宝石,你可能能够找到答案
https://github.com/mojombo/chronic/ https://github.com/mojombo/chronic/
Since you already use Rails, you don't need the includes, but this works in pure Ruby as well for reference. 由于您已经使用了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
I think you should probably use a library if you're needing to branch out into more interesting logic, but if what you've described is all you need, the code below should help 我认为你应该使用一个库,如果你需要扩展到更有趣的逻辑,但如果你所描述的只是你需要的,下面的代码应该有帮助
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
Loop through the last month and next month, grab the tuesdays, group by month, take the 2nd and the 2nd last tuesday of the current month (If you actually do want the 4th tuesday, just change -2 to 3) and the 2nd tuesday of the next month and then choose the first one after the provided date. 循环上个月和下个月,抓住星期二,逐个月,取当月的第二个和第二个星期二(如果你确实想要第4个星期二,只需要改变-2到3)和第二个星期二下个月然后在提供的日期之后选择第一个。
Here's some tests, 4 tuesdays in month, 5 tuesdays in month, random, and your examples: 这里有一些测试,每月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
which produces 哪个产生
[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
I'm sure it could be simplified, and I'd love to hear some suggestions :) (way too late &tired to even bother figuring out what the actual range should be for valid dates ie smaller than -31..62) 我确信它可以简化,我很想听到一些建议:)(太晚了,太累了,甚至懒得弄清楚有效日期的实际范围应该是多少,即小于-31..62)
so here is the code that will resolve a weekday for a given week in a month (what you asked for with little sugar). 所以这里的代码将解决一个月中给定周的工作日(你用少量糖要求)。 You should not have problems if you are running inside rails framework.
如果您在rails框架内运行,那么您应该没有问题。 Otherwise make sure you have active_support gem installed.
否则,请确保已安装active_support gem。 Method name is stupid so feel free to change it :)
方法名称是愚蠢的,所以随时改变它:)
usage: get_next_day_of_week(some_date, :friday, 1)
用法:
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
I use the following to calculate Microsoft's patch Tuesday date. 我使用以下内容来计算Microsoft的补丁周二日期。 It was adapted from some C# code.
它改编自一些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))
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.