Ruby/Rails如何在DateTime范围内迭代月份



我正在尝试从Rails表中的数据构建一个图形:每个时间片段的销售产品数量。

因为图应该能够显示最后一个小时(在1分钟的步骤中),最后一天(在1小时的步骤中),最后一周(在1天的步骤中),最后一个月(在1天的步骤中)等,我试图通过迭代一系列DateTime对象来减少代码重复:

# To prevent code-duplication, iterate over different time ranges.
times = {
    :hour=>{newer_than: 1.hour.ago, timestep: :minute},
    :day=>{newer_than: 1.day.ago, timestep: :hour},
    :week=>{newer_than: 1.week.ago, , timestep: :day},
    :month=>{newer_than: 1.week.ago, , timestep: :day}
}

products = Product.all
# Create symbols `:beginning_of_minute`, `:beginning_of_hour`, etc. These are used to group products and timestamps by.
times.each do|name, t| 
  t[:beginning_of] = ("beginning_of_" << t[:timestep].to_s).to_sym 
end 
graphs = times.map do |name, t|
   graphpoints = {}
   seconds_in_a_day = 1.day.to_f
   step_ratio = 1.send(t[:timestep]).ago.to_f / seconds_in_a_day
   time_enum = 1.send(t[:timestep]).ago.to_datetime.step(DateTime.now, step_ratio)
   time_enum.each do |timestep|
       graphpoints[time_moment.send(timehash[:beginning_of]).to_datetime] = []
   end
   # Load all products that are visible in this graph size
   visible_products = products.select {|p| p.created_at >= t.newer_than}
   # Group them per graph point
   grouped_products = visible_products.group_by {|item| item.created_at.send(timehash[:beginning_of]).to_datetime}
   graphpoints.merge!(grouped_products)
   {
      points: graphpoints,
      labels: graphpoints.keys
   }
end

此代码适用于所有具有恒定大小的时间间隔(小时、天、周)。然而,对于几个月,它使用30天的step_ratio: 1.month / 1.day == 30。显然,每个月的天数并不是恒定的。在我的脚本中,这会导致一个月可能被"跳过",从而从图中丢失。

如何解决这个问题?如何在记住不同月份的天数的同时迭代月份?

如果您必须在一个巨大的数组中选择month,只需在两个Date:class之间设置范围。

(1.year.ago.to_date..DateTime.now.to_date)).select{|date| date.day==1}.each do |date|
  p date
end

使用groupdate gem。例如(从文档中修改的示例):

visible_products = Product.where("created_at > ?", 1.week.ago).group_by_day
# {
#   2015-07-29 00:00:00 UTC => 50,
#   2013-07-30 00:00:00 UTC => 100,
#   2013-08-02 00:00:00 UTC => 34
# }

也,这将会更快,因为你的分组/计数将由数据库本身完成,而不需要通过Product.all调用传递所有的记录到你的Rails代码,而不需要为每一个创建ActiveRecord对象(甚至不相关)。

最新更新