这是您可以做到的一种方式。
代码
require 'date'
def missing_months(dates)
a = dates.map { |s| d = Date.strptime(s, '%a, %d %b %Y'); d - d.day + 1 }
(all_months_in_range(*a.minmax) -a).map { |d| d.strftime('%b %Y') }
end
def all_months_in_range(f,l)
(12*(l.year-f.year)+l.month-f.month+1).times.map do |i|
y,m = (f.month+i).divmod(12)
y += f.year
(m=12; y-=1) if m ==0
Date.new(y,m)
end
end
示例
dates = ['Wed, 23 Oct 2013', 'Mon, 18 Nov 2013', 'Fri, 22 Nov 2013',
'Fri, 14 Nov 2014', 'Tue, 18 Nov 2014', 'Fri, 26 Dec 2014',
'Mon, 13 Jan 2014', 'Tue, 28 Jan 2014', 'Mon, 03 Feb 2014',
'Mon, 31 Mar 2014', 'Mon, 07 Apr 2014', 'Tue, 10 Jun 2014',
'Mon, 30 Jun 2014', 'Mon, 22 Sep 2014', 'Mon, 06 Oct 2014',
'Mon, 10 Feb 2014', 'Tue, 18 Feb 2014', 'Fri, 07 Mar 2014',
'Thu, 15 Jan 2015', 'Mon, 23 Mar 2015', 'Mon, 20 Apr 2015']
missing_months(dates)
#=> ["Dec 2013", "May 2014", "Jul 2014", "Aug 2014", "Feb 2015"]
注意dates 不需要排序。
说明
对于上面的例子:
a = dates.map { |s| d = Date.strptime(s, '%a, %d %b %Y'); d - d.day + 1 }
#=> [#<Date: 2013-10-01 ((2456567j,0s,0n),+0s,2299161j)>,
# #<Date: 2013-11-01 ((2456598j,0s,0n),+0s,2299161j)>,
# ...
# #<Date: 2015-04-01 ((2457114j,0s,0n),+0s,2299161j)>]
请注意,这些日期中的每一个都在每月的第一天。接下来,获取这些日期中的第一个和最后一个:
f,l = a.minmax
f #=> [#<Date: 2013-10-01 ((2456567j,0s,0n),+0s,2299161j)>,
l #=> #<Date: 2015-04-01 ((2457114j,0s,0n),+0s,2299161j)>]
现在将f 和l 传递给all_months_in_range 以创建一个数组,其中包含f 和l 之间每个月的第一天的日期对象。
b = all_months_in_range(f,l)
#=> [#<Date: 2013-10-01 ((2456567j,0s,0n),+0s,2299161j)>,
# #<Date: 2013-11-01 ((2456598j,0s,0n),+0s,2299161j)>,
# ...
# #<Date: 2015-04-01 ((2457114j,0s,0n),+0s,2299161j)>]
b.size #=> 19
我将跳过对这个辅助方法的解释,因为它非常简单。
计算数组 b 和 a 之间的差异,以获得缺失的月初日期:
c = b-a
#=> [#<Date: 2013-12-01 ((2456628j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-05-01 ((2456779j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-07-01 ((2456840j,0s,0n),+0s,2299161j)>,
# #<Date: 2014-08-01 ((2456871j,0s,0n),+0s,2299161j)>,
# #<Date: 2015-02-01 ((2457055j,0s,0n),+0s,2299161j)>]
最后,将这些日期转换为所需的格式:
c.map { |d| d.strftime('%b %Y') }
#=> ["Dec 2013", "May 2014", "Jul 2014", "Aug 2014", "Feb 2015"]
附录:阅读@Sid 的回答后,我发现我可以使用Date#next_month 为自己的辅助方法省去一些麻烦:
def all_months_in_range(f,l)
(12*(l.year-f.year)+l.month-f.month+1).times.map { |i| f.next_month(i) }
end