我需要在几个月的范围内每月创建日志文件。因此我需要给定范围内的所有 [year,month] 元组
你如何迭代日期?
如果我每天都需要迭代,怎么办?
例如:
((Date.today - 90)..Date.today).map{|d| [d.year, d.month]}.uniq
#=> [[2012, 12], [2013, 1], [2013, 2], [2013, 3]]
RubyDate
支持连续几天的生产,并提供了next_month
一种可用于在几个月内有效迭代的方法。
这是一种适应输入精度的通用方法:
require 'date'
def date_tuples(from,to)
prec = from.size
start = Date.new(*from)
finish = Date.new(*to)
filter_on = [:day,:mon].first(3-prec)
filter = ->(d) { filter_on.all? {|attr| d.send(attr) == 1 } }
(start..finish)
.select(&filter)
.map { |d| [d.year,d.mon,d.day].first(prec) }
end
[7] pry(main)> date_tuples([2012],[2015])
=> [[2012], [2013], [2014], [2015]]
[8] pry(main)> date_tuples([2012,10],[2013,3])
=> [[2012, 10], [2012, 11], [2012, 12], [2013, 1], [2013, 2], [2013, 3]]
[9] pry(main)> date_tuples([2012,10,25],[2012,11,6])
=> [[2012, 10, 25],
[2012, 10, 26],
[2012, 10, 27],
[2012, 10, 28],
[2012, 10, 29],
[2012, 10, 30],
[2012, 10, 31],
[2012, 11, 1],
[2012, 11, 2],
[2012, 11, 3],
[2012, 11, 4],
[2012, 11, 5],
[2012, 11, 6]]
我想出了这个解决方案来生成范围内所有 [year,month] 元组的列表:
first=[2012,10]
last=[2013,03]
(first[0]..last[0]).to_a.product((1..12).to_a).select{|ym|(first..last).cover?(ym)}
=> [[2012, 10], [2012, 11], [2012, 12], [2013, 1], [2013, 2], [2013, 3]]
start_date = 1.year.ago.to_date
end_date = Date.current.yesterday
monthly = [Date.new(start_date.year, start_date.beginning_of_month.month, 1)]
(start_date..end_date).each do |d|
month_date = Date.new(d.year, d.next_month.beginning_of_month.month, 1)
monthly << month_date if monthly.exclude?(month_date) && month_date < end_date - 1.month
end
monthly
=> [Fri, 01 Sep 2017, Sun, 01 Oct 2017, Wed, 01 Nov 2017, Fri, 01 Dec 2017, Sun, 01 Jan 2017, Thu, 01 Feb 2018, Thu, 01 Mar 2018, Sun, 01 Apr 2018, Tue, 01 May 2018, Fri, 01 Jun 2018, Sun, 01 Jul 2018, Wed, 01 Aug 2018]
这是我为解决此问题而写的一种方法。这是为处理哈希数据而设计的,例如:{Sun, 01 Jan 2012=>58, Wed, 01 Feb 2012=>0, Thu, 01 Mar 2012=>0} 但可以很容易地修改为数组数据。
请参阅:https ://github.com/StephenOTT/add_missing_dates_ruby我提供了一个工作代码示例
但关键的代码是:
def addMissingMonths (datesHash)
count = 0
result = {}
datesHash.keys.each do |x|
if x != datesHash.keys.last
(x+1.month).upto(datesHash.keys[count+1]-1.month) do |a|
result[a.at_beginning_of_month] = 0
end
end
count += 1
end
return result.merge!(datesHash)
end
要看的关键内容是:(x+1.month).upto(datesHash.keys[count+1]-1.month)
require 'date'
Time.new(2011).to_date.upto(Time.now.to_date) do |a|
puts ""+a.day.to_s+","+a.month.to_s+","+a.year.to_s
end
或获取您的月/年元组:
require 'date'
result = []
Time.new(2002).to_date.upto(Time.now.to_date) do |a|
result << [a.month,a.year]
end
result.uniq!
从日期开始使用 upto 方法:http ://ruby-doc.org/stdlib-2.0/libdoc/date/rdoc/Date.html#method-i-upto
这里的大多数答案都需要在该范围内的每一天进行迭代。这意味着如果您在几年内这样做,您可能会有一个包含数千次迭代的循环。
此代码段创建了一个循环,其步骤数与该范围内的月份数一样多,这样效率更高:
require 'date'
start_date = Date.new(2010, 10)
end_date = Date.new(2011, 4)
current_month = start_date
date_tuples = []
while current_month <= end_date
date_tuples << [current_month.year, current_month.month]
current_month = current_month.next_month
end
pp date_tuples
# => [[2010, 10], [2010, 11], [2010, 12], [2011, 1], [2011, 2], [2011, 3], [2011, 4]]
这种方法的一个怪癖是它只适用于当月第一天的日期。因此,如果您有这样的日期Date.new(2020, 10, 12)
,则需要将其转换为该月的第一天