Почему этот rails-запрос ведет себя по-разному в зависимости от часового пояса?

StackOverflow https://stackoverflow.com/questions/1262825

Вопрос

У меня есть запрос rails, основанный на времени, который имеет какое-то странное поведение, зависящее от часового пояса, хотя, насколько я знаю, я использую UTC.В двух словах, эти запросы дают разные ответы:

>> Model.find(:all,:conditions=>['created_at<=?',(Time.now-1.hours).gmtime]).length
=> 279
>> Model.find(:all,:conditions=>['created_at<=?',(Time.now-1.hours)]).length
=> 280

Где база данных на самом деле содержит одну модель, созданную за последний час, а общее количество моделей равно 280.Таким образом, только первый запрос является правильным.

Однако, в environment.rb у меня есть:

config.time_zone = 'UTC'

Системный часовой пояс (как указано в 'date') - BST (который равен GMT + 1) - так что каким-то образом это заканчивается обработкой как UTC и прерыванием запросов.

Это вызывает у меня всевозможные проблемы, поскольку мне нужно параметризовать запрос, передаваемый в разное время для действия (которые затем преобразуются с помощью Time.parse()) , и даже несмотря на то, что я отправляю во времени UTC, эта проблема с "отключением на один час" сильно влияет на летнее время.Даже использование '.gmtime()', похоже, не всегда это исправляет.

Очевидно, что разница каким-то образом вызвана неявным преобразованием где-то, в результате чего BST неправильно трактуется как UTC, но почему?Разве rails не хранит временные метки в формате UTC?Разве часовой пояс класса Time не известен?Я использую Rails 2.2.2

Итак, что же здесь происходит - и каков безопасный способ обойти это программированием?

редактировать, некоторая дополнительная информация, чтобы показать, что делают DB и Time class:

>> Model.find(:last).created_at
=> Tue, 11 Aug 2009 20:31:07 UTC +00:00
>> Time.now
=> Tue Aug 11 22:00:18 +0100 2009
>> Time.now.gmtime
=> Tue Aug 11 21:00:22 UTC 2009
Это было полезно?

Решение

Тот самый Time класс напрямую не осведомлен о вашем настроенном часовом поясе.Rails 2.1 добавил кучу поддержки часовых поясов, но Time по-прежнему будет действовать в соответствии с вашим местным часовым поясом.Вот почему Time.now возвращает первое время.

Чего вы, вероятно, хотите, так это взаимодействовать с Time.zone.Вы можете вызывать методы для этого, как для самого класса Time, но он вернет его в указанном часовом поясе.

Time.zone.now # => Tue, 11 Aug 2009 21:31:45 UTC +00:00
Time.zone.parse("2:30 PM Aug 23, 2009") # => Sun, 23 Aug 2009 14:30:00 UTC +00:00

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

Item.all(:conditions => ["published_at <= ?", Time.now.utc])

Кроме того, вместо Time.now-1.hour делай 1.hour.ago.Это легче читать, и Rails автоматически будет использовать настроенный часовой пояс.

Другие советы

Часовой пояс, который вам нужно установить, — Великобритания, он будет автоматически обрабатывать BST.

Time.zone = 'UK'
Time.zone.now
 => Sun, 17 Oct 2010 02:09:54 BST +01:00
start_date_format = DateTime.strptime(@start_date, date_format)
start_date_format_with_hour = 
DateTime.strptime((start_date_format.to_i + timezone_offset*60*60).to_s,'%s').strftime(date_format)

end_date_format = DateTime.strptime(@end_date, date_format)
end_date_format_with_hour = DateTime.strptime((end_date_format.to_i + timezone_offset*60*60).to_s,'%s').strftime(date_format)

@filters_date = "invoices.created_at >= ? AND invoices.created_at < ?", start_date_format_with_hour, end_date_format_with_hour
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top