Time.now против Time.zone.now в Rails

June 4, 2010 Ruby Ruby on Rails базы данных

Функции Time.now и Time.zone.now в Ruby on Rails практически идентичны. Возвращают одни и те же значения, ведут себя одинаково. Из-за этого легко перепутать и использовать более короткую формулировку Time.now. А зря – по крайней мере, если ты используешь часовой пояс, отличный от UTC.

В чем же разница между этими функциями? А вот в чем:

>> Time.now.class
=> Time
>> Time.now.to_s :db
=> "2010-06-04 19:00:00"
>> Time.zone.now.class
=> ActiveSupport::TimeWithZone
>> Time.zone.now.to_s :db
=> "2010-06-04 16:00:11"

Дело в том, что Rails, начиная с версии 2.1, хранят время в базе в UTC, а при сохранении и чтении переводят его из и в часовой пояс, используемый в приложении.

За перевод времени в UTC отвечает, как ни странно, метод to_s(:db). Точнее странно то, что, хоть он и доступен у объекта типа Time, работает он неверно и отдает время в текущем часовом поясе. Если использовать Time.now в условиях запроса – они сместятся на определенное количество часов. Если записывать Time.now в базу – в базу запишется неправильное значение, потому что при чтении рельсы лишний раз добавят к нему смещение часового пояса.

Короче, наиболее простым и адекватным решением этой проблемы будет замена по всему проекту Time.now на Time.zone.now.

…А еще из-за это проблемы не стоит использовать в запросах функцию MySQL NOW() и аналогичные, поскольку они ничего не знают о настройках рельсов.

Buy Me a Coffee at ko-fi.com