在Ruby中检查两个时间戳是否是同一天

30

我在Ruby中的Date、Datetime和Time这三个概念比较混淆。而且,我的应用对时区很敏感,我不确定如何在保持时区鲁棒性的同时,在这三个概念之间进行转换。

如何检查两个Unix时间戳(自纪元以来的秒数)是否表示同一天?(实际上,使用本地时间或UTC都可以;虽然我更喜欢使用本地时间,但只要是一致的,我就可以设计解决方案)。

4个回答

56
使用标准库将时间对象转换为日期。
require 'date'

Time.at(x).to_date === Time.at(y).to_date

Date对象有===方法,如果两个Date对象表示同一天,则返回true。


Ruby中的日期和时间是时区感知的。因此,如果您使用UTC创建Date对象,则它将在UTC中。如果您使用不同的时区创建它们,则它们将在该时区中。 - Anurag
感谢@KL-7。我不确定为什么在1.8.7中将其设为私有,但似乎核心团队发现在1.9中将其公开作为公共方法很有用。 - Anurag
1
三个等号表示近似相等,这似乎有点令人惊讶,但这就是RDoc所说的! - Andrew Grimm
工作得很好。非常有帮助。 - nick
@DarlanDieterich:Time已经是“带时间的日期”。在这里,我们试图忽略时间组件。 - Sergio Tulentsev
显示剩余3条评论

7

ActiveSupport为Time类定义了一个不错的to_date方法,如下所示:

class Time
  def to_date
    ::Date.new(year, month, day)
  end
end

使用它,您可以像这样比较时间戳:

Time.at(ts1).to_date === Time.at(ts2).to_date

以下是一种不需要扩展Time类的较少争议的方法:

t1 = Time.at(ts1) # local time corresponding to given unix timestamp ts1
t2 = Time.at(ts2)
Date.new(t1.year, t1.month, t1.day) === Date.new(t2.year, t2.month, t2.day)

这个问题被标记为 Ruby;我认为假设他在使用Rails是不公平的。 - maček
是的,我没有使用Rails。另外,Time.at(1324196871).to_date == Time.at(1324253810).to_date 对我来说返回false...它是否自动将时间戳转换为本地时间? - chimeracoder
但是他可以自己定义这个辅助方法。代码已经提供了。 :-) - Sergio Tulentsev
1
我个人倾向于不扩展类,除非必须这样做。扩展会导致代码更难理解(当有新人加入项目时尤为重要)。 - Sergio Tulentsev
@thebackhand,我更新了答案。 为了比较由“Date”对象表示的天数,您应该使用“===”而不是“==”。 通常最好避免扩展基类,但我习惯于一些简单的事情,比如Rails中的“Time〜to_date”,不明白为什么我们在标准库中没有它们。 我只是指出了它在ActiveSupport中的实现方式,您可以在不扩展“Time”类的情况下执行相同的操作:“t = Time.at(ts);d = Date.new(t.year,t.month,t.day)”。 - KL-7
显示剩余5条评论

3
Time.at(ts1).day == Time.at(ts2).day && (ts1 - ts2).abs <= 86400

或者

t1 = Time.at(ts1)
t2 = Time.at(ts2)
t1.yday == t2.yday && t1.year == t2.year

在第一种情况下,我们确保时间戳之间的间隔不超过一天(因为#day返回月份的日期,如果没有这个额外的检查,4月1日将等于5月1日)。
另一种方法是获取一年中的日期并确保它们属于同一年。
这些方法在1.8和1.9中同样适用。

2
我们可以使用时间的 beginning_of_day 方法并进行比较: t1.beginning_of_day == t2.beginning_of_day 这样时区就不会受到影响。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接