Rails 日期时间和赛程
我有以下固定装置:
link_1:
user: tom
image: boy1
created_at: <%= 5.day.ago %>
我尝试了以下请求:
Links.where("Date(created_at) = ?", 5.day.ago.to_date)
答案:
[]
grrrrr....正在打字...正在打字...抓挠... 我终于尝试了:
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)
知道吗?
I had the following fixture:
link_1:
user: tom
image: boy1
created_at: <%= 5.day.ago %>
I tried the following request:
Links.where("Date(created_at) = ?", 5.day.ago.to_date)
Answer:
[]
grrrr....typing...typing...scratching...
I finally tried:
link_1:
user: tom
image: boy1
created_at: <%= 5.day.ago.to_date %>
and
Links.where("Date(created_at) = ?", 5.day.ago.to_date)
finally answers
[#<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">]
What I was expecting, but why did I need to put to_date? It is not clear to me, because when I create an object without specifying the creation date, I can select them with the following where clause without issue:
Links.where("Date(created_at) = ?", Date.today)
Any idea?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在固定装置中,您应该:
您的查询将是:
让 ActiveRecord 处理有关将数据移出和移入数据库的详细信息。我们使用 ORM 是有原因的。
参考。
In fixtures you should have:
Your query will be a:
Let ActiveRecord taking care of the details about moving data from and to the database. We are using an ORM for a reason.
Reference.
我推测这是因为创建夹具和调用查询之间的时间差。
5 天前 + 0.00025 毫秒 > 5 天前,
我不确定日期时间的精度是多少,但这是我能想到的唯一可能性。当您将其转换为日期时,您删除了无关的时间信息并使两者相等。
I would speculate that it's because of the time difference between when the fixture was created and when the query was called.
5 days ago + 0.00025 ms > 5 days ago
I'm not sure what the precision is for datetimes, but it's the only possibility I can think of. When you converted it to a date, your removed the extraneous time information and rendered the two equal.
created_at
是一个 DateTime 字段,而5.days.ago
实际上返回一个 DateTime 对象。该对象将具有与调用它时相同的时间设置,例如。 2014 年 8 月 23 日星期六 10:30:37,这就是放入数据库的内容。在失败的情况下,当您稍后再次调用
5.days.ago
时(即使在同一执行中),新时间可能会有所不同,例如。 2014 年 8 月 23 日星期六 10:30:38。因此你可以看到它们不相等,并且你不会得到任何匹配项。当您附加
.to_date
时,您将获得一个 Date 对象,该对象没有时间部分。当它被持久化到数据库或在查询中使用时,它将始终被视为时间为 00:00:00(午夜)。因此,日期和时间将匹配(只要您不尝试运行装置并在午夜精确查询)created_at
is a DateTime field, and5.days.ago
effectively returns a DateTime object. This object will have the same time set as at the moment it is called, eg. Sat, 23 Aug 2014 10:30:37, and this is what gets put into the database.In your failing case, when you call
5.days.ago
again later (even in the same execution) the new time will likely differ, eg. Sat, 23 Aug 2014 10:30:38. Therefore you can see that they are not equal, and you will get no matches.When you append
.to_date
, you get a Date object, which has no time component. When this gets persisted to the database, or used in your query, it will always be regarded as having a time of 00:00:00 (midnight). Therefore the date and time will match, (as long as you don't try running the fixtures and query exactly over midnight)两种情况之间的区别在于,当您调用
to_date
时,您会丢失时间值,因此最终结果是将created_at
时间戳设置为当天的午夜。您还可以避免从TimeWithZone
进行时区转换。坦率地说,我们没有足够的信息来推测除此之外正在发生的事情。要准确了解发生了什么,最好的办法是查看log/test.log
中的查询 - 如果您没有看到查询,可以通过设置打开它们将
更改为config/environments/test.rb
中的 log_level:debug
。请随意在此处复制并粘贴 SQL 查询。@Ibz 还提出了一个好点:使用
.to_s(:db)
是一个好主意,因为固定文件 ERB 被评估为字符串,然后作为 YAML 读入,这可能会导致一些问题将值转换为字符串。使用.to_s(:db)
将解决此问题,但为了将来避免这种情况(并获得一堆附加功能),我建议使用 factory_girl 而不是固定装置。在处理测试日期时,此类问题很常见 - 特别是当您尝试通过两个日期或时间戳的相等性进行查询时。为了解决这些问题,我建议选择过去的任意固定日期/时间,而不是执行
5.days.ago
,或者如果您确实需要使用动态日期/时间,请使用 Timecop gem 用于控制/冻结测试中的时间。The difference between your two cases is that when you call
to_date
, you lose the time value, and so the end result is acreated_at
timestamp set to midnight of that day. You also avoid the time zone translation fromTimeWithZone
. Frankly, we don't have enough information to conjecture what is happening beyond this. To see exactly what is going on, your best bet is to look at the queries in yourlog/test.log
- if you don't see queries, you can turn them on by settinglog_level
to:debug
inconfig/environments/test.rb
. Feel free to copy and paste the SQL queries here.@Ibz also raises a good point: using
.to_s(:db)
is a good idea, because the fixture file ERB is evaluated to a string and then read in as YAML, which can cause some issues with casting of values to strings. Using.to_s(:db)
will fix this problem, but to avoid this in the future (and gain a bunch of additional features), I'd recommend using factory_girl instead of fixtures.These kinds of issues are common when dealing with testing dates - particularly if you are trying to query by equality of two dates or timestamps. To tackle these issues, I recommend either picking arbitrary fixed dates/times in the past instead of doing
5.days.ago
, or if you do need to use dynamic dates/times, use the Timecop gem to control/freeze time within your tests.