簡體   English   中英

Ruby / Rails如何在DateTime范圍內迭代幾個月?

[英]Ruby/Rails how to iterate months over a DateTime range?

我正在嘗試從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天的1.month / 1.day == 301.month / 1.day == 30 顯然,幾個月的天數不是恆定的。 在我的腳本中,這導致一個月可能被“跳過”,因此從圖中丟失。

如何解決這個問題? 如何在幾個月中進行迭代,同時牢記幾個月中不同的天數?

使用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對象(甚至無關緊要)。

如果必須在一個巨大的數組中選擇月份,則只需在兩個Date:class之間進行選擇即可。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM