我试图循环数年和数月。如果@user.created_at
为November 2015
,那么我想获得此输出:
November 2015
December 2015
January 2016
February 2016
March 2016
我尝试了以下内容:
Hash[(@user.created_at.month..Date.today.month).map { |month| [ month, 0 ] }].merge(...)
但上面的代码返回
堆栈级别太深
因为它循环11..3
。
我怎么能弄清楚这个问题?
答案 0 :(得分:4)
如果您想计算即将到来的月份/年份,可以随时使用advance
:
start = @user.created_at.to_date.beginning_of_month
Hash[(0..6).collect { |n| [ start.advance(months: n).month, 0 ] }]
这应该适当地逐步完成几天/几个月。你可能只想坚持日期而不仅仅是月份数。
如果你想做“到今天”,那就试试这个:
date = @user.created_at.to_date.beginning_of_month
stop = Date.today.beginning_of_month
hash = { }
while (date <= stop)
hash[date] = 0
date = date.advance(months: 1)
end
答案 1 :(得分:2)
您可以做的一件事就是将每个日期转换为&#34;月份数&#34;这一年乘以12加上零基月,然后迭代它们,例如:
from_date = Date.new(2015, 11) # Nov. 1, 2015
to_date = Date.today # Mar. 22, 2016
nov2015 = from_date.year * 12 + (from_date.month - 1)
# => 24190
nov2015.divmod(12)
# => [2015, 10]
mar2016 = to_date.year * 12 + (to_date.month - 1)
# => 24194
mar2016.divmod(12)
# => [2016, 2]
请注意,这些月份从零开始,因此2
为3月,10
为11月。正如预期的那样,nov2015
和mar2016
相差四个。现在我们可以从一个迭代到另一个:
nov2015.upto(mar2016) do |month_num|
year, month = month_num.divmod(12)
puts Date.new(year, month + 1).strftime("%B %Y")
end
# => November 2015
# December 2015
# January 2016
# February 2016
# March 2016
完美!但是如果我们可以将它放入一个返回Enumerator的方法中,那么我们可以使用任何Enumerable方法(each
,map
,each_cons
,你可以命名它。 )上:
def months_enum(from_date, to_date)
from = from_date.year * 12 + from_date.month - 1
to = to_date.year * 12 + to_date.month - 1
Enumerator.new do |y|
from.upto(to) do |n|
year, month = n.divmod(12)
y << Date.new(year, month + 1)
end
end
end
然后:
from = Date.new(2015, 11, 1)
to = Date.today
months_enum(from, to).each do |date|
puts date.strftime("%Y-%m")
end
# -> 2015-11
# 2015-12
# 2016-01
# 2016-02
# 2016-03
p months_enum(from, to).map {|date| date.strftime("%B %Y") }
# => [ "November 2015",
# "December 2015",
# "January 2016",
# "February 2016",
# "March 2016" ]
答案 2 :(得分:1)
require 'date'
from_date = Date.new(2015, 11)
to_date = Date.today
until from_date > to_date do
puts from_date.strftime("%B %Y")
from_date = from_date.next_month
end
#November 2015
#December 2015
#January 2016
#February 2016
#March 2016
答案 3 :(得分:0)
我将从用户的created_at日期开始并循环直到它已经赶上今天:
start = @user.created_at
months = []
while start <= Time.zone.now
months << [start.strftime('%B'), start.year]
start += 1.month
end
months
结果:
=> [["November", 2015], ["December", 2015], ["January", 2016], ["February", 2016], ["March", 2016]]
这样您就不必计算created_at和now之间的月差异。
答案 4 :(得分:0)
这是一个纯Ruby解决方案。
require 'date'
如果给出
prev_date = "November 2015"
m = Date.strptime(prev_date,"%B %Y")
#=> #<Date: 2015-11-01 ((2457328j,0s,0n),+0s,2299161j)>
然后
n = Date.today
n -= n.day - 1
#=> #<Date: 2016-03-01 ((2457449j,0s,0n),+0s,2299161j)>
while m <= n
puts "#{Date::MONTHNAMES[m.month].ljust(8)} #{m.year}"
m = m >> 1
end
November 2015
December 2015
January 2016
February 2016
March 2016
答案 5 :(得分:0)
使用Integer#month()
方法在Rails中向日期对象添加月份将为您完成所有多年的包装。如果用户的加入日期在某个月的31日,那么它也足够聪明,不会跳过少于31天的月份。如果您在1月31日添加一个月,则返回值将是2月28日(如果是闰年,则为29)。
date_joined = @user.created_at
now = Time.now
until date_joined.month > now.month && date_joined.year == now.year
puts date_joined.strftime("%B %Y")
date_joined += 1.month
end