Rails如何基于日期范围创建月份数组

23

我有一个例子:

  range = start.to_date..(end.to_date + 1.day)

end和start是日期。

如何基于这个范围创建一个月份数组?

例如:

我有日期23/1/2012和15/3/2012。

月份为1月、2月和3月。

我想要得到一个类似这样的数组 ["1/1/2012", "1/2/2012", "1/3/2012"]

如果范围在2012年6月25日至2012年10月10日之间,则数组将为:["1/6/2012", "1/7/2012", "1/8/2012", "1/9/2012", "1/10/2012"]


假设步长间隔为1个月? - Lorenz Lo Sauer
请看这里:https://dev59.com/qm025IYBdhLWcg3wpHl_ - Lorenz Lo Sauer
我刚刚更新了我的问题,并附上了示例。 - Rails beginner
1
这个答案answer可能会对你有所帮助。 - rogeliog
4个回答

37
require 'date'

date_from  = Date.parse('2011-10-14')
date_to    = Date.parse('2012-04-30')
date_range = date_from..date_to

date_months = date_range.map {|d| Date.new(d.year, d.month, 1) }.uniq
date_months.map {|d| d.strftime "%d/%m/%Y" }
# => ["01/10/2011", "01/11/2011", "01/12/2011", "01/01/2012",
#     "01/02/2012", "01/03/2012", "01/04/2012"] 

10

Rails ActiveSupport 核心扩展包含了一个 Date 的方法:beginning_of_month。你可以按照以下方式编写你的函数:

def beginning_of_month_date_list(start, finish)
  (start.to_date..finish.to_date).map(&:beginning_of_month).uniq.map(&:to_s)
end

注意事项:这段代码可以更高效地编写,假定开始和结束日期是按照期望的顺序排列的,但除此之外,它应该会给你所需要的月份。你还可以重写代码,通过向 #to_s 方法传递格式符号来获取期望的月份格式。


我已经尝试过这个但没有成功。我需要在我的循环中使用它,更多信息请参见此处:http://stackoverflow.com/questions/12544533/rails-how-to-create-chart-data-for-each-month-between-2-dates - Rails beginner
看到您得到的结果会有帮助。 - rossta

5

我对这里的性能很好奇,因此测试了一些变化。以下是更加优化性能的解决方案(在我的基准测试中比已接受的解决方案快约8倍)。通过每次增加一个月,我们可以去掉调用uniq的步骤,这可以节省相当多的时间。

start_date = 1.year.ago.to_date
end_date = Date.today

dates = []
date = start_date.beginning_of_month

while date <= end_date.beginning_of_month
  dates << date.to_date.to_s
  date += 1.month
end

dates

#=> ["2019-02-01", "2019-03-01", "2019-04-01", "2019-05-01", "2019-06-01", "2019-07-01", "2019-08-01", "2019-09-01", "2019-10-01", "2019-11-01", "2019-12-01", "2020-01-01", "2020-02-01"]

基准测试结果:

Comparison:
month increment loop:    17788.3 i/s
accepted solution:     2140.1 i/s - 8.31x  slower

基准测试代码的Gist


0

类似于上面的一个解决方案,使用 beginning_of_month.. 但是占用更少的空间(通过使用 Set)并且对于使用 inject 更整洁。

(start_month..end_month).inject(Set.new) { |s, i| s << i.beginning_of_month; s }.to_a

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接