如何迭代日期?
如果我需要每天迭代,该怎么办?
((Date.today - 90)..Date.today).map{|d| [d.year, d.month]}.uniq
#=> [[2012, 12], [2013, 1], [2013, 2], [2013, 3]]
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]]
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]
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
参见:
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'
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)
这样的日期,您需要将其转换为该月的第一天
年。
def month_start_dates_between_years(start_year, end_year)
years = (start_year..end_year).to_a
month_tuples = years.product((1..12).to_a)
return month_tuples.map { |tuple| Date.new(*tuple) }
end
date1 = Date.new(2024,4,25)
date2 = Date.new(2025,2,8)
month_distance = 12 * (date2.year - date1.year) + date2.month - date1.month + 1
month_distance.times.map { |m| d = date1 + m.months; [d.year, d.month] }
# => [[2024, 4], [2024, 5], [2024, 6], [2024, 7], [2024, 8], [2024, 9], [2024, 10], [2024, 11], [2024, 12], [2025, 1], [2025, 2]]
(start_date..end_date).to_a.map { |date| date.strftime("%B %Y") }.uniq