3

特定のユーザーのタイム ゾーンで、過去 30 日間の 1 日あたりのインプレッション数を表示しようとしています。問題は、タイムゾーンによってカウントが常に同じであるとは限らず、それをクエリに反映するのに苦労しています。

たとえば、CDT で 1 日目の午後 11:00 (-5) に発生した 2 つのインプレッションと、CDT の午前 1:00 に発生した 1 つのインプレッションを取り上げます。UTC (+0) を使用してクエリを実行すると、初日に 2 回、2 日目に 1 回ではなく、2 日目に発生した 3 回のインプレッションがすべて取得されます。どちらの CDT 時間も UTC の 2 日目に着陸します。

これが私が今やっていることです。ここで単純なものが欠けているに違いないことはわかっています:

start = 30.days.ago
finish = Time.now

# if the users time zone offset is less than 0 we need to make sure
# that we make it all the way to the newest data
if Time.now.in_time_zone(current_user.timezone) < 0
  start += 1.day
  finish += 1.day
end

(start.to_date...finish.to_date).map do |date|
  # get the start of the day in the user's timezone in utc so we can properly
  # query the database
  day = date.to_time.in_time_zone(current_user.timezone).beginning_of_day.utc
  [ (day.to_i * 1000), Impression.total_on(day) ]
end

印象モデル:

class Impression < ActiveRecord::Base
  def self.total_on(day)
    count(conditions: [ "created_at >= ? AND created_at < ?", day, day + 24.hours ])
  end
end

私は他の投稿を見てきましたが、データベースに多くの面倒な作業を処理させることができるようですが、AT TIME ZONEやのようなものを使用してもうまくいきませんでしたINTERVAL.

私が持っていないものは本当に汚れているように見えます。明らかな何かが欠けているに違いないことはわかっています。どんな助けでも大歓迎です。

4

2 に答える 2

2

わかりました、この素晴らしい記事の助けを借りて、私はそれを理解したと思います. 私の問題は、システム Ruby の時間メソッドとタイム ゾーンを意識した Rails メソッドの違いを知らなかったことが原因でした。このようにaround_filter を使用してユーザーに正しいタイム ゾーンを設定すると、組み込みの Rails メソッドを使用してコードをかなり単純化することができました。

# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  around_filter :set_time_zone

  def set_time_zone
    if logged_in?
      Time.use_zone(current_user.time_zone) { yield }
    else
      yield
    end
  end
end

# app/controllers/charts_controller.rb

start = 30.days.ago
finish = Time.current

(start.to_date...finish.to_date).map do |date|
  # Rails method that uses Time.zone set in application_controller.rb
  # It's then converted to the proper time in utc
  time = date.beginning_of_day.utc
  [ (time.to_i * 1000), Impression.total_on(time) ]
end

# app/models/impression.rb

class Impression < ActiveRecord::Base
  def self.total_on(time)
    # time.tomorrow returns the time 24 hours after the instance time. so it stays UTC
    count(conditions: [ "created_at >= ? AND created_at < ?", time, time.tomorrow ])
  end
end

他にもできることはあるかもしれませんが、これでだいぶ楽になりました。

于 2013-06-25T22:17:10.217 に答える