Время и время рельсов

У меня было следующее приспособление:

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, чтобы контролировать/заморозить время в рамках ваших тестов.