您需要 Time 对象是否有特定原因?
我们很清楚,Ruby 中的 Time 类不仅仅是“没有日期的 DateTime”。正如“What's the difference between DateTime and Time in Ruby?”解释的那样,“时间是 POSIX 标准 time_t 的包装,即自 1970 年 1 月 1 日以来的秒数。”与 DateTime 一样,Time 对象仍然具有年、月和日,因此使用 Time 并不能真正获得任何好处。实际上并没有办法使用 Time 或 DateTime 来表示小时和分钟。
我认为,你可以用 Time 做的最好的事情是:
date_time = DateTime.now
seconds = date_time.hour * 60 * 60 + date_time.minute * 60
time = Time.at(seconds)
# => 1970-01-01 09:58
...但是您仍然需要致电 time.hour 和 time.min 来了解小时和分钟。
如果您只是在寻找一种轻量级的数据结构来表示小时和分钟对,那么您不妨自己动手:
HourAndMinute = Struct.new(:hour, :minute) do
def self.from_datetime(date_time)
new(date_time.hour, date_time.minute)
end
end
hm = HourAndMinute.from_datetime(DateTime.now)
# => #<struct HourAndMinute hour=15, minute=58>
hm.to_h
# => { :hour => 15, :minute => 58 }
hm.to_a
# => [ 15, 58 ]
编辑回复:
我有一个存储约会的变量——这个变量是一个 DateTime 对象。我有两个存储位置的开始和结束时间的表字段。我需要检查为该约会安排的时间是否介于开始时间和结束时间之间。
啊,看来你有点XY problem。这现在更有意义了。
如果没有更多信息,我将假设您的“存储位置开始和结束时间的字段”是 MySQL TIME 列,称为 start_time 和 end_time。给定 MySQL TIME 列,Rails 将值转换为 Time 对象with the date component set to 1/1/2000。所以如果你的数据库有start_time = '09:00' 和end_time = '17:00' 的值,Rails 会给你这样的 Time 对象:
start_time = Time.new(2000, 1, 1, 9, 0) # => 2000-01-01 09:00:00 ...
end_time = Time.new(2000, 1, 1, 17, 0) # => 2000-01-01 17:00:00 ...
现在你说你的约会时间是 DateTime,所以我们称它为 appointment_datetime 并假设它是明天上午 10:30:
appointment_datetime = DateTime.new(2014, 11, 18, 10, 30) # => 2014-11-18 10:30:00 ...
所以现在重新表述您的问题:我们如何判断appointment_datetime 的时间 部分是否介于start_time 和end_time 的时间 部分之间。答案是,我们需要更改start_time 和end_time 的date 部分以匹配appointment_datetime 的date 部分,或者反过来。因为改变一件事比改变两件事容易,让我们反过来做,改变appointment_datetime以匹配start_time和end_time(并且,因为这两个是时间对象,我们将创建一个时间对象):
appointment_time = DateTime.new(2000, 1, 1, appointment_datetime.hour, appointment_datetime.minute)
# => 2000-01-01 10:30:00 ...
现在我们可以直接比较它们了:
if appointment_time >= start_time && appointment_time <= end_time
puts "Appointment time is good!"
end
# Or, more succinctly:
if (start_time..end_time).cover?(appointment_time)
puts "Appointment time is good!"
end
当然,您会希望将所有这些都包含在一个方法中,也许在您的 Location 模型中(我再次假设它具有 start_time 和 end_time 属性):
class Location < ActiveRecord::Base
# ...
def appointment_time_good?(appointment_datetime)
appointment_time = DateTime.new(2000, 1, 1,
appointment_datetime.hour, appointment_datetime.minute)
(start_time..end_time).cover?(appointment_time)
end
end
location = Location.find(12) # => #<Location id: 12, ...>
location.appointment_time_good?(appointment_time) # => true
希望对你有帮助!
附:实现这一点的另一种方法是完全放弃日期/时间对象并进行直接的数字比较:
def appointment_time_good?(appointment_datetime)
appointment_hour_min = [ appointment_datetime.hour, appointment_datetime.minute ]
appointment_hour_min >= [ start_time.hour, start_time.min ]
&& appointment_hour_min <= [ end_time.hour, end_time.min ]
end