Время и время рельсов
У меня было следующее приспособление:
link_1:
user: tom
image: boy1
created_at: <%= 5.day.ago %>
Я попробовал следующий запрос:
Links.where("Date(created_at) = ?", 5.day.ago.to_date)
Ответ:
[]
Grrrr.... печатает... печатает... царапины...
Я, наконец, попробовал:
link_1:
user: tom
image: boy1
created_at: <%= 5.day.ago.to_date %>
и
Links.where("Date(created_at) = ?", 5.day.ago.to_date)
наконец отвечает
[#<Link id: 298486374, user_id: 1038054164, image_id: 482586125, created_at: "2010-11-28 00:00:00", updated_at: "2010-12-03 21:32:19">]
Что я ожидал, но зачем мне нужно поставить to_date? Мне это непонятно, потому что когда я создаю объект без указания даты создания, я могу выбрать их со следующим предложением where без проблем:
Links.where("Date(created_at) = ?", Date.today)
Любая идея?
Ответы
Ответ 1
В светильниках вы должны иметь:
created_at: <%= 5.day.ago.to_s(:db) %>
Ваш запрос будет выглядеть следующим образом:
Links.where("created_at = ?", ...
Пусть ActiveRecord позаботится о деталях перемещения данных и из базы данных. Мы используем ORM по какой-то причине.
Ссылка.
Ответ 2
Я бы предположил, что это из-за разницы во времени между тем, когда был создан прибор и когда был вызван запрос.
5 дней назад + 0.00025 мs > 5 дней назад
Я не уверен, что такое точность для datetimes, но это единственная возможность, о которой я могу думать. Когда вы преобразовали его в дату, вы удалили информацию о постороннем времени и отобрали два равных.
Ответ 3
created_at
- это поле DateTime, а 5.days.ago
эффективно возвращает объект DateTime. Этот объект будет иметь то же время, что и в момент его вызова, например. Sat, 23 Aug 2014 10:30: 37, и это то, что попадает в базу данных.
В случае сбоя, когда вы снова вызываете 5.days.ago
позже (даже в том же исполнении), новое время, вероятно, будет отличаться, например. Сб, 23 авг. 2014 10:30: 38. Поэтому вы можете видеть, что они не равны, и вы не получите совпадений.
Когда вы добавляете .to_date
, вы получаете объект Date, у которого нет компонента времени. Когда это будет сохраняться в базе данных или использоваться в вашем запросе, это всегда будет считаться временем 00:00:00 (полночь). Поэтому дата и время будут совпадать (пока вы не будете запускать приборы и запрашивать точно за полночь)
Ответ 4
Различие между двумя вашими случаями заключается в том, что при вызове to_date
вы теряете значение времени, поэтому конечным результатом является отметка created_at
, установленная в полночь того дня. Вы также избегаете перевода часового пояса из TimeWithZone
. Честно говоря, у нас недостаточно информации, чтобы предположить, что происходит дальше этого. Чтобы узнать, что именно происходит, лучше всего посмотреть на запросы в log/test.log
- если вы не видите запросы, вы можете включить их, установив log_level
в :debug
в config/environments/test.rb
. Не стесняйтесь копировать и вставлять SQL-запросы здесь.
@Ibz также поднимает хорошую точку: использование .to_s(:db)
является хорошей идеей, потому что файл привязки ERB оценивается по строке и затем считывается как YAML, что может вызвать некоторые проблемы с литьем значений в строки. Использование .to_s(:db)
устранит эту проблему, но чтобы избежать этого в будущем (и получить кучу дополнительных функций), я бы рекомендовал использовать factory_girl вместо светильников.
Эти проблемы часто встречаются при работе с датами тестирования, особенно если вы пытаетесь запросить равенство двух дат или временных меток. Чтобы решить эти проблемы, я рекомендую либо собирать произвольные фиксированные даты/время в прошлом, а не делать 5.days.ago
, или если вам нужно использовать динамические даты/время, используйте Timecop gem, чтобы контролировать/заморозить время в рамках ваших тестов.