【问题标题】:Ruby on Rails parsing time from datetime, not as stringRuby on Rails 从日期时间解析时间,而不是字符串
【发布时间】:2015-01-12 08:39:11
【问题描述】:

我正在尝试从 DateTime 对象(在我的示例中表示为“at”)中提取时间分量。我该怎么做,我完全被难住了? (我不想像这里那样用strftime 将其解析为字符串):

@session_date.at.strftime("%H:%M")

我真的很想将小时和分钟作为 Time 对象返回。

【问题讨论】:

  • 为什么不呢?这似乎是这样做的规范方式?
  • 因为出于我的目的,我不希望将 DateTime 对象解析为字符串,所以我需要几分钟和几小时来测试它是否介于开始时间和结束时间之间(两个 Time 对象)跨度>
  • 阅读@Jordan 的回复

标签: ruby-on-rails ruby datetime


【解决方案1】:

您需要 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.hourtime.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_timeend_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_timeend_time时间 部分之间。答案是,我们需要更改start_timeend_timedate 部分以匹配appointment_datetimedate 部分,或者反过来。因为改变一件事比改变两件事容易,让我们反过来做,改变appointment_datetime以匹配start_timeend_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_timeend_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

【讨论】:

  • 嗯,我不认为我想要一个键值对。也许如果我详细说明我的目的,它可能会有所帮助。我有一个存储约会的变量——这个变量是一个 DateTime 对象。我有两个存储位置的开始和结束时间的表字段。我需要检查为该约会安排的时间是否介于开始时间和结束时间之间。
  • 非常感谢!最后一部分肯定解决了我的问题,我会支持你,但遗憾的是我没有足够的声誉来这样做。
【解决方案2】:

如果您正在寻找从现在开始的时间(这在 Rails 应用程序中很常见),那么这可能是一个不错的阅读:http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-time_ago_in_words

【讨论】:

    【解决方案3】:

    如果你有一个 DateTime 对象:

    date_time = DateTime.now
    
    date_time.hour
    # => 16
    date_time.minute
    # => 1
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-24
      • 1970-01-01
      • 1970-01-01
      • 2014-01-05
      • 1970-01-01
      相关资源
      最近更新 更多