Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/452.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails 按小时分组并在rails中使用用户时区?_Ruby On Rails_Ruby On Rails 3_Activerecord - Fatal编程技术网

Ruby on rails 按小时分组并在rails中使用用户时区?

Ruby on rails 按小时分组并在rails中使用用户时区?,ruby-on-rails,ruby-on-rails-3,activerecord,Ruby On Rails,Ruby On Rails 3,Activerecord,为了构建一个漂亮的图表,我必须显示在过去30天中,用户每天进行多少api调用。到目前为止,我没有任何问题。需要注意的是,数据库和系统时区以UTC为单位,但大多数用户位于太平洋时间(GMT-8) 为了按使用日期对api使用情况进行分组,我可以执行以下操作 ApiCall. where(user_id: @user.id). where("requested_at > ?", Time.zone.now.to_date - 30.days). group("date(request

为了构建一个漂亮的图表,我必须显示在过去30天中,用户每天进行多少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:00GMT-8,一名用户在加利福尼亚州进行API调用。数据库中的API调用以时间2012-12-14 05:00:00存储(因为它是以GMT为单位的,所以增加了8小时)

现在对于那个用户,如果我去查看我的日常使用情况,通过我所做的查询,它将显示我的api调用不是在2012-12-14的21:00:00进行的,因为在数据库上它存储为2012-12-14 05:00:00,对于用户,api使用情况将显示他在第二天进行了api调用,并且他会认为系统工作不正常


因此,简单地说,如何根据用户时区而不是数据库时区对api调用进行分组?

是的,通过使用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

稍后我将添加一个悬赏,看看是否有人可以告诉我关于使用rails和时区的此类报告的更好解决方案。您可以为请求设置时区,并在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_过滤器中设置时区

Time.zone = current_user.time_zone if logged_in?

我不认为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范围:。

我认为将所有记录存储在UTC中是一种良好的做法,因此无需转换任何内容,并且可以正确计算时间间隔。向用户显示时间时,仅转换为用户的本地时区

有点晚了,但这里是Postgresql的答案:

首先定义此变量以使内容更具可读性:

requested_at_day = "date(requested_at AT TIME ZONE \'UTC\'
              AT TIME ZONE \'#{Time.zone.tzinfo.identifier}\')"
然后:


是的,我知道Time.zone,我知道使用ruby对记录进行分组,虽然让db引擎进行分组更有效,所以我真正想要的是一种很好的rails方法来处理时区,同时让引擎进行复杂的操作。我已经在UTC中存储了所有内容,问题是我必须按天或小时分组,因为用户有不同的时区。好吧,在这种情况下很容易,因为一切都是UTC,当用户查询他在某一天(他的本地时间)进行的api调用时,只需将其本地时间转换为数据库中等效的UTC时间,并使用该时间构造查询。在您的示例中,自本地时间12/14 21:00起用户的api调用将成为自12/15 5:00起db的UTC时间,但这将使我回到原始问题。假设你位于洛杉矶,所以是GMT-8。数据库以GMT+0存储日期和时间。你昨天晚上10点打了50个api电话,今天凌晨4点又打了50个。db在今天开店,第一家在早上6点开店,另一家在下午12点开店。如果我按天分组,db将按时区GMT+0分组,所以它会说您今天进行了100次api调用,但我需要它说您今天进行了50次api调用,并进行了正确的时区转换,我正在寻找一种更干净的方法来利用rails时区。在您的例子中,这是如何定义“今天”的问题,您需要说用户“今天”进行了50次api调用,这意味着您从用户的角度定义了“今天”,因此这意味着您必须在处理请求时将其转换为正确的服务器时间范围。假设用户在GMT-8上午5点登录,并且他对“今天”查看他的api调用感兴趣,这将转化为从GMT+0 8AM到现在(即GMT+0 1PM)查找他的api调用的请求。每个用户都会有不同的“今天”,我认为这没关系,因为分析数据是呈现给用户的。
ApiCall.
  where(user_id: @user.id).
  where("requested_at > ?", Time.zone.now.to_date - 30.days).
  group(requested_at_day).
  select("count(*) as qty, #{requested_at_day} as requested_at_day").all