时区任意改变

时间:2017-10-25 22:56:01

标签: ruby-on-rails postgresql ruby-on-rails-5 rails-activerecord

我使用gem groupdate在控制器的操作中执行此类查询:

Event.where.not(user_id: [1, 3]).group_by_week(:created_at, week_start: :mon, last: 13, reverse: true).count

通过刷新网页执行几个顺序查询会不时更改SQL查询。应用程序的默认时区似乎正在发生变化,即使在此操作/视图中设置时区,也不会发生这种情况。

这可能是什么原因?如何/在哪里调试?

UTC在application.rb中设置为默认时区。由上述相同查询引起的两个不同SQL查询的示例:

SELECT COUNT(*) AS count_all, (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'Etc/UTC') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'Etc/UTC' AS date_trunc_week_created_at_timestamptz_interval_0_day_interval_ FROM "events" WHERE ("events"."user_id" NOT IN (1, 3, 290, 339)) AND (created_at >= '2017-07-31 00:00:00' AND created_at <= '2017-10-25 22:23:42.184226') GROUP BY (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'Etc/UTC') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'Etc/UTC'

SELECT COUNT(*) AS count_all, (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'America/New_York') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'America/New_York' AS date_trunc_week_created_at_timestamptz_interval_0_day_interval_ FROM "events" WHERE ("events"."user_id" NOT IN (1, 3, 290, 339)) AND (created_at >= '2017-07-31 04:00:00' AND created_at <= '2017-10-25 22:24:57.912750') GROUP BY (DATE_TRUNC('week', (created_at::timestamptz - INTERVAL '0 day' - INTERVAL '0 second') AT TIME ZONE 'America/New_York') + INTERVAL '0 day' + INTERVAL '0 second') AT TIME ZONE 'America/New_York'

1 个答案:

答案 0 :(得分:1)

方法def time_zone来自class Magic,它有一个attr_accessor :options。当您创建实例@magic = Magic.new(period, options)时,您可以在options参数中设置您的时区truefalse或其他值

基于此参数,def time_zone方法将设置并返回@time_zone

def time_zone
  @time_zone ||= begin
    time_zone = "Etc/UTC" if options[:time_zone] == false
    time_zone ||= options[:time_zone] || Groupdate.time_zone || (Groupdate.time_zone == false && "Etc/UTC") || Time.zone || "Etc/UTC"
    time_zone.is_a?(ActiveSupport::TimeZone) ? time_zone : ActiveSupport::TimeZone[time_zone]
  end
end

您使用Groupdate.time_zone 设置时区 :time_zone是模块Groupdate

中的attr_accessor
module Groupdate
  class Error < RuntimeError; end

  PERIODS = [:second, :minute, :hour, :day, :week, :month, :quarter, :year, :day_of_week, :hour_of_day, :minute_of_hour, :day_of_month, :month_of_year]
  # backwards compatibility for anyone who happened to use it
  FIELDS = PERIODS
  METHODS = PERIODS.map { |v| :"group_by_#{v}" } + [:group_by_period]

  mattr_accessor :week_start, :day_start, :time_zone, :dates
  self.week_start = :sun
  self.day_start = 0
  self.dates = true
end

这就是def time_zone内的方法magic.rb正在搜索值...

time_zone ||= options[:time_zone] || Groupdate.time_zone || (Groupdate.time_zone == false && "Etc/UTC") || Time.zone || "Etc/UTC"

从上面的表达式中可以看出,它来自options[:time_zone]实例的MagicGroupdate.time_zone模块中的Groupdate,或者它是来自您的服务器或桌面的Time.zone,或Etc/UTC

所以我认为您可以通过遵循指南来解决这个问题,它为您提供了两个选择:

解决方案

  

Time Zones

     

默认时区是Time.zone。改为:

Groupdate.time_zone = "Pacific Time (US & Canada)"

User.group_by_week(:created_at, time_zone: "Pacific Time (US & Canada)").count
# {
#   Sun, 06 Mar 2016 => 70,
#   Sun, 13 Mar 2016 => 54,
#   Sun, 20 Mar 2016 => 80
# }
  

时区对象也有效。要在Rails中查看可用时区列表,请运行rake time:zones:all。