3

適切なグラフを作成するために、過去 30 日間にユーザーが 1 日に行った API 呼び出しの数を表示する必要があります。これまでのところ、問題はありませんでした。データベースとシステムのタイムゾーンは UTC ですが、ほとんどのユーザーは太平洋時間 (GMT -8) を使用していることに注意してください。

使用日ごとにグループ化されたAPIの使用状況を取得するには、次のようなことができます

ApiCall.
  where(user_id: @user.id).
  where("requested_at > ?", Time.zone.now.to_date - 30.days).
  group("date(requested_at)").
  select("count(*) as qty, date(requested_at) as requested_at").all

ここでの問題は、カリフォルニアにいるユーザーの時間がイギリスにいるユーザーの時間と大きく異なることです。それが私が失敗しているところです。

2012 年 12 月 14 日 21:00:00 GMT -8 に、カリフォルニアにいるユーザーが API 呼び出しを行います。DB の API CALL は、時刻 2012-12-14 05:00:00 で保存されます (GMT であるため、8 時間が追加されます)。

そのユーザーについて、私が行ったクエリで毎日の使用状況を確認すると、2012 年 12 月 14 日の 21:00:00 に API 呼び出しが行われなかったことが示されます。 2012-12-14 05:00:00 であり、ユーザーの場合、API の使用は、その API 呼び出しを翌日に行ったことを示し、システムが正常に動作していないと考えます。

つまり、データベースのタイムゾーンではなく、ユーザーのタイムゾーンに基づいて API 呼び出しをグループ化するにはどうすればよいでしょうか?

4

5 に答える 5

2

リクエストのタイムゾーンを設定し、Rails で日付の並べ替えを行うことができます。

ApiCall.
  where(user_id: @user.id).
  where("requested_at > ?", Time.zone.now.to_date - 30.days).
  group_by({|api_call| api_call.requested_at.to_date})

通常、Rails では、コントローラ アクションの before_filter でタイム ゾーンを設定します。

Time.zone = current_user.time_zone if logged_in?
于 2012-12-16T17:15:26.397 に答える
2

はい、mysql convert timezone 関数を使用することにより、それは良い解決策ではありませんが、動作します

ApiCall.
  where(user_id: @user.id).
  where("requested_at > ?", Time.zone.now.to_date - 30.days).
  group("date(convert_tz(requested_at, '+00:00', '-08:00'))").
  select("count(*) as qty, date(requested_at) as requested_at").all

後で賞金を追加して、レールとタイムゾーンを使用したこの種のレポートのより良い解決策について誰かが教えてくれるかどうかを確認します

于 2012-12-16T13:42:27.603 に答える
2

Rails には、「グループ」を実行する前にユーザーのタイムゾーンで DB の日付を変換するこの種のスコープが付属しているとは思いません。

ただし、それを処理する独自のスコープを定義できます。たとえば、次のようになります。

class ApiCall  
  scope :group_by_date_in_timezone, lambda{|date_column| 
    group("date(convert_tz(#{date_column}, '+00:00', '#{Time.zone.formatted_offset}'))")
  }

次に、クエリが少し明確になります。

ApiCall.
  where(user_id: @user.id).
  where("requested_at > ?", Time.zone.now.to_date - 30.days).
  group_by_date_in_timezone(:requested_at).
  select("count(*) as qty, requested_at").all

  # 'date(requested_at) as requested_at' would be also in DB Time zone
  # Instead we can select 'requested_at' to let Rails do the user timezone conversion
  # you can easily convert it to a date later with #to_date

このスコープは他のモデルにも役立つ場合があります。その場合、この質問の回答に従って、グローバル ActiveRecord スコープとして定義できます: Hacking ActiveRecord: add global named scope .

于 2012-12-20T10:03:19.110 に答える
-1

すべてのレコードを UTC で保存することをお勧めします。そのため、何も変換する必要がなく、時間間隔が正しく計算されます。ユーザーに時刻を表示する場合にのみ、ユーザーのローカル タイム ゾーンに変換します。

于 2012-12-23T23:53:37.297 に答える