迭代日期以查找日期之间的天数

时间:2015-04-21 03:20:52

标签: ruby date methods

我有一系列日期,我需要让每个日期找出下一个日期之间的差异,例如

a= {1=>03-01-2015, 2=>03-10-2015, 3=>03-15-2015, 4=>03-27-2015}

完整的对象看起来像这样......

#<Transaction:0xc413c58 @id="KYYEZEPedacrwBkpqDk8C5Yy04BqvJIXJdYXJ", @account="Ppp575Ke19T8PxrAdMrNUq4Ox4AQVrHMLa5D0", @date="2013-10-23", @amount=100, @name="COMED", @meta={"is_risky"=>false, "location"=>{"store_number"=>"10782"}}, @location=nil, @pending=false, @score={"location"=>{}, "name"=>0.2}, @type={"primary"=>"unresolved"}, @category=nil, @category_id=nil>] 

应该返回

{9,5,12} #the days between each 2 dates

这是我到目前为止所拥有的......

@collect_transactions = (@user.transactions.find_all { |t| t.name == 'due_at' })
@date_difference = @collect_transactions.map(&:date).each_cons(2) { |a,b| b-a }

我不确定each_cons是否是正确的方法,但我现在的回答是......

NoMethodError: undefined method `-' for "2015-01-15":String

不计算日子......任何建议都会受到高度赞赏

2 个答案:

答案 0 :(得分:3)

是的,Enumerable#each_cons是要走的路。您只需要将日期字符串转换为日期对象。你可以这样做。

<强>代码

require 'date'

def date_diffs(h)    
  h.values.
    map { |s| Date.strptime(s,'%m-%d-%Y') }.
    each_cons(2).
    map { |d1,d2| (d2-d1).to_i }
end

示例

h = { 1=>"03-01-2015", 2=>"03-10-2015", 3=>"03-15-2015", 4=>"03-27-2015" }

date_diffs(h)
  #=> [9, 5, 12]

<强>讨论

从编辑到您的问题,您可能需要使用日期格式字符串'%Y-%m-%d'。另一种选择是使用Date::parse而不是Date::strptime。 (我通常更喜欢strptime,因为它要求更高。)

当然,您必须确保哈希值的顺序正确。如果您使用的是1.9之前的Ruby版本(当不能保证散列键的顺序,甚至是键盘顺序的概念),或者您使用的是更新版本(保持密钥插入顺序),但是不确定键的顺序,你可以这样做第一步:

values = h.values_at(*(1..4))
  #=> ["03-01-2015", "03-10-2015", "03-15-2015", "03-27-2015"] 

<强>解释

我们有:

b = h.values
  #=> ["03-01-2015", "03-10-2015", "03-15-2015", "03-27-2015"] 
c = b.map { |s| Date.strptime(s,'%m-%d-%Y') }
  #=> [#<Date: 2015-03-01 ((2457083j,0s,0n),+0s,2299161j)>,
  #    #<Date: 2015-03-10 ((2457092j,0s,0n),+0s,2299161j)>,
  #    #<Date: 2015-03-15 ((2457097j,0s,0n),+0s,2299161j)>,
  #    #<Date: 2015-03-27 ((2457109j,0s,0n),+0s,2299161j)>] 
d = c.each_cons(2)
  #=> #<Enumerator: [#<Date: 2015-03-01....

我们发现枚举器d包含d.size #=> 3个元素。它将传递给块并分配给块变量的第一个元素是:

d1,d2 = d.next
   #=> [#<Date: 2015-03-01 ((2457083j,0s,0n),+0s,2299161j)>,
   #    #<Date: 2015-03-10 ((2457092j,0s,0n),+0s,2299161j)>] 
d1 #=> #<Date: 2015-03-01 ((2457083j,0s,0n),+0s,2299161j)> 
d2 #=> #<Date: 2015-03-10 ((2457092j,0s,0n),+0s,2299161j)> 

我们计算有理数:

d2-d1 #=> (9/1)

(因为它总是一个整数)我们可以转换为整数:

(9/1).to_i #=> 9

所以我们获得:

d.map { |d1,d2| (d2-d1).to_i }   
  #=> [9, 5, 12] 

为什么Date#-返回有理数而不是整数? @Stefan给出了一个很好的解释here

答案 1 :(得分:0)

根据您的日期格式是mm-dd-YYYY还是YYYY-mm-dd(您的问题中有点含糊不清),您可以使用Rails助手String#to_date转换为{ {1}}对象。 (这只适用于后者。)

Date

无论哪种方式,您可能希望重构代码以将日期存储为数据库中的正确日期数据类型。