2015-03-04 2 views
0

Это странное поведение недавно привлекло мое внимание, в то время как я тестировал свое приложение Rails в локальной среде, в которой я использую around_filter, чтобы установить часовой пояс для зарегистрированного пользователя (часовой пояс по умолчанию - UTC).timezones и делать аналитику на таблицах

Что я сделал, так это то, что я зарегистрировал нового пользователя в своем приложении. Мое текущее время было 10pm GMT-5 (3 марта), и время создания этого пользователя было сохранено в базе данных до 4:00 UTC (4 марта). Теперь я знаю, что это время сохраняется в базе данных с настройками часового пояса, но здесь возникает проблема:

Я использую график для визуального представления пользователей, зарегистрированных ежедневно, и когда я вызывал следующую функцию, чтобы сообщить мне номер пользователи, зарегистрированные в течение последних нескольких дней:

from ||= Date.today - 1.month 
to ||= Date.today 
where(created_at: from..to).group('DATE(created_at)').count 

было бы сказать, что этот пользователь был зарегистрирован в 4 марта, в то время как это было на самом деле зарегистрировано 3 марта с моей точки зрения.

Мой вопрос: Как мне позвонить, где функция и группа по столбцу created_at, чтобы даты были правильно изменены (в соответствии с моим часовым поясом)?

Или есть что-то еще, что я должен делать по-другому?

ответ

1

Я не рубист, поэтому я позволю кому-то дать конкретный код, но я могу ответить с общей алгоритмической точки зрения.

Если вы сохраняете UTC в базе данных, вам также нужен UTC.

При определении диапазона запроса (from и to) вам необходимо узнать время начала и окончания для «сегодня» в вашем локальном часовом поясе и преобразовать их в UTC.

К примеру, я в часовом поясе США Тихого океана, а сегодня 7 марта, 2015.

from: 2015-03-07T00:00:00-08:00 = 2015-03-07T08:00:00Z 
    to: 2015-03-08T00:00:00-08:00 = 2015-03-08T08:00:00Z 

Если вы хотите вычесть месяц, как вы показали в примере, сделайте это до того вы конвертируете в UTC. И следить за летнее время. Нет никакой гарантии, что смещения будут одинаковыми.

Кроме того, вы захотите использовать диапазон полуоткрытых интервалов, который исключает верхнюю границу. Я верю в Ruby, что это делается с тремя точками (...) вместо двух (по крайней мере, согласно this).

Группировка обычно немного сложнее. Я предполагаю, что это запрос к базе данных, не так ли? Ну, если у db, на который вы запрашиваете, есть поддержка часового пояса, вы можете использовать его для преобразования даты в свой часовой пояс перед группировкой. Что-то вроде этого (псевдокод):

groupby(DATE(CONVERT_TZ(created_at,'UTC','America/Los_Angeles'))) 

Поскольку вы не утверждал, что БД вы используете, я не могу быть более точным. CONVERT_TZ доступен в MySQL, и я считаю, что Oracle и Postgres имеют поддержку часового пояса.

1

Date.todaywill default to your system's set timezone (который, кстати, должен всегда быть UTC, here's why), так что если вы хотите использовать UTC, просто сделать Time.zone.now.to_date, если рельсы устанавливается в UTC

В противном случае вы должны сделать

Time.use_zone('UTC') do 
    Time.zone.now.to_date 
end 

После этого вы должны показать даты created_at, выполнив object.created_at.in_time_zone('EST')
, чтобы показать его в вашем текущем часовом поясе