所以我有两个红宝石日期对象,我想每月都迭代它们。例如,如果我有Date.new(2008,12)和Date.new(2009,3),它会产生我2008-12,2009-1,2009-2,2009-3(当然是Date对象)。我尝试使用范围,但它每天都会产生。我看到了日期的步骤方法,但它只允许我传递天数(每个月有不同的天数)。有人有主意吗?用日期对象迭代每个月
回答
我已经添加下面的方法来Date类:
class Date
def all_months_until to
from = self
from, to = to, from if from > to
m = Date.new from.year, from.month
result = []
while m <= to
result << m
m >>= 1
end
result
end
end
您可以使用它喜欢:
>> t = Date.today
=> #<Date: 2009-11-12 (4910295/2,0,2299161)>
>> t.all_months_until(t+100)
=> [#<Date: 2009-11-01 (4910273/2,0,2299161)>, #<Date: 2009-12-01 (4910333/2,0,2299161)>, #<Date: 2010-01-01 (4910395/2,0,2299161)>, #<Date: 2010-02-01 (4910457/2,0,2299161)>]
好了,所以,更rubyish做法恕我直言,是沿东西:
class Month<Date
def succ
self >> 1
end
end
and
>> t = Month.today
=> #<Month: 2009-11-13 (4910297/2,0,2299161)>
>> (t..t+100).to_a
=> [#<Month: 2009-11-13 (4910297/2,0,2299161)>, #<Month: 2009-12-13 (4910357/2,0,2299161)>, #<Month: 2010-01-13 (4910419/2,0,2299161)>, #<Month: 2010-02-13 (4910481/2,0,2299161)>]
但是,你需要小心使用月份的第一天(或月实现这样的逻辑)...
我发现我有时需要为此产生个月的选择列表时。关键是在日期的>>
运营商,该运营商将该日期提前一个月。
def months_between(start_month, end_month)
months = []
ptr = start_month
while ptr <= end_month do
months << ptr
ptr = ptr >> 1
end
months
end
results = months_between(Date.new(2008,12), Date.new(2009,3))
当然,您可以在循环中格式化结果。
months << "#{Date::MONTHNAMES[ptr.month]} #{ptr.year}"
将返回月份名称和年份(“2009年3月”),而不是Date对象。请注意,返回的Date对象将在月份的第一天设置。
这是这里唯一有效的答案,因为它解释了日期#>> – mikezter 2012-11-15 20:30:14
我想出了以下解决方案。这是一个混合日期范围,可以为年和月添加迭代器。它产生完整范围的子范围。
require 'date'
module EnumDateRange
def each_year
years = []
if block_given?
grouped_dates = self.group_by {|date| date.year}
grouped_dates.each_value do |dates|
years << (yield (dates[0]..dates[-1]))
end
else
return self.enum_for(:each_year)
end
years
end
def each_month
months = []
if block_given?
self.each_year do |range|
grouped_dates = range.group_by {|date| date.month}
grouped_dates.each_value do |dates|
months << (yield (dates[0]..dates[-1]))
end
end
else
return self.enum_for(:each_month)
end
months
end
end
first = Date.parse('2009-01-01')
last = Date.parse('2011-01-01')
complete_range = first...last
complete_range.extend EnumDateRange
complete_range.each_year {|year_range| puts "Year: #{year_range}"}
complete_range.each_month {|month_range| puts "Month: #{month_range}"}
会给你:
Year: 2009-01-01..2009-12-31
Year: 2010-01-01..2010-12-31
Month: 2009-01-01..2009-01-31
Month: 2009-02-01..2009-02-28
Month: 2009-03-01..2009-03-31
Month: 2009-04-01..2009-04-30
Month: 2009-05-01..2009-05-31
Month: 2009-06-01..2009-06-30
Month: 2009-07-01..2009-07-31
Month: 2009-08-01..2009-08-31
Month: 2009-09-01..2009-09-30
Month: 2009-10-01..2009-10-31
Month: 2009-11-01..2009-11-30
Month: 2009-12-01..2009-12-31
Month: 2010-01-01..2010-01-31
Month: 2010-02-01..2010-02-28
Month: 2010-03-01..2010-03-31
Month: 2010-04-01..2010-04-30
Month: 2010-05-01..2010-05-31
Month: 2010-06-01..2010-06-30
Month: 2010-07-01..2010-07-31
Month: 2010-08-01..2010-08-31
Month: 2010-09-01..2010-09-30
Month: 2010-10-01..2010-10-31
Month: 2010-11-01..2010-11-30
Month: 2010-12-01..2010-12-31
作为一个辅助方法:
def iterate(d1, d2)
date = d1
while date <= d2
yield date
date = date >> 1
end
end
用法:
start_date = Date.new(2008, 12)
end_date = Date.new(2009, 3)
iterate(start_date, end_date){|date| puts date}
或者,如果你喜欢猴子补丁日期:
class Date
def upto(end_date)
date = self
while date <= end_date
yield date
date = date >> 1
end
end
end
用法:
start_date = Date.new(2008, 12)
end_date = Date.new(2009, 3)
start_date.upto(end_date){|date| puts date}
这是一件很红宝石:
每个月的第一天
(Date.new(2008, 12)..Date.new(2011, 12)).select {|d| d.day == 1}
它会给你第一天的数组范围内的每个月。每个月
(Date.new(2008, 12)..Date.new(2012, 01)).select {|d| d.day == 1}.map {|d| d - 1}.drop(1)
的
最后一天只需注意,结束日期必须是您的最终范围之后的一个月。
这是最优雅的! – 2011-12-04 13:18:17
对于大日期范围效率低下 – 2013-01-10 18:18:11
真的吗? 4000年是一个足够大的日期范围? Benchmark.measure {(Date.new(1,1).. Date.new(4000,12))。select {| d | d.day == 1}} => 1.170000 0.000000 1.170000(1.181518) – 2013-01-10 18:32:45
MonthRange.new(date1..date2).each { |month| ... }
MonthRange.new(date1..date2).map { |month| ... }
如果您使用此迭代器类,则可以使用所有Enumerable方法。我也使它处理字符串,以便它可以采取形式输入。
# Iterate over months in a range
class MonthRange
include Enumerable
def initialize(range)
@start_date = range.first
@end_date = range.last
@start_date = Date.parse(@start_date) unless @start_date.respond_to? :month
@end_date = Date.parse(@end_date) unless @end_date.respond_to? :month
end
def each
current_month = @start_date.beginning_of_month
while current_month <= @end_date do
yield current_month
current_month = (current_month + 1.month).beginning_of_month
end
end
end
对于starts_of_month,您需要ActiveSupport(来自rails) – 2015-08-18 13:58:15
def each_month(date, end_date)
ret = []
(ret << date; date += 1.month) while date <= end_date
ret
end
Date.new(2014,1,1).upto(Date.today).map {|date| "#{date.to_s[0..-4]}"}.uniq
会给你每个月包括它是一年中的字符串表示。
- 1. 计算两个日期之间的月数,迭代每个月的函数
- 2. 在两个日期排名 - 每个日期迭代
- 3. jquery每个都没有迭代对象
- 4. 集团每月的每个星期日?
- 5. 月份日格式的日期对象
- 6. 每个月与每周的正确日期对齐?
- 7. XSL对于每个迭代
- 8. 如何每月迭代bigquery代码?
- 9. 如何在每个对象(JavaScript)中用JSON对象迭代JSON对象?
- 10. 使用javascript返回一个月份中每一天的日期对象数组
- 11. 迭代对象数组,并将每个对象保存到MongoDB
- 12. 如何选择每个月的每月最大日期行
- 13. 在datetime对象中过滤日期月
- 14. 显示每个月的日期范围
- 15. 日期筛选不适用于每月的第一个月
- 16. 调用迭代器迭代对象
- 17. 使用mocks检查每个对象在迭代期间是否被分析过
- 18. JQuery的$。每()JSON对象数组迭代
- 19. 使用Date对象查找一个月中的所有日期?
- 20. C++/OF迭代每次迭代更改属性的对象?
- 21. 迭代在一个对象
- 22. 迭代一个JavaScript对象
- 23. 如何获得每个月的最短日期为六个月?
- 24. 在Android中获取日期月份值的日期对象?
- 25. 从日期集合中选择每个月的最后日期
- 26. MySQL从日期列中获取每个月的最后日期
- 27. 得到时间序列对象每月日期R作为一个POSIXlt
- 28. 如何使用每个迭代类的对象
- 29. GROUP BY选择每月定期日期
- 30. 如何使用逻辑迭代对象列表:在jsp中迭代并显示每个对象属性值?
希望得到更多的红宝石... – Andrius 2009-11-12 22:51:40
那么,我想到的唯一“红宝石”方法就是定义“Month”类(通过继承Date),定义succ方法并使用Range。 – 2009-11-13 09:29:51
谢谢姆兰登!这个all_months_until方法正是我所期待的。 – jspooner 2010-09-16 23:11:42