【问题标题】:ActiveRecord returns "argument out of range" for Time of 26:12ActiveRecord 在 26:12 的时间返回“参数超出范围”
【发布时间】:2011-11-23 04:34:18
【问题描述】:

似乎 ActiveRecord 和 Ruby 的 Time 对象在超过 24:00 的时间上表现不佳。但是我的数据库有很多这样的,因为它们代表午夜之后的时间,但被认为是在同一天。这是我data provider的设计决定:

注意:跨越多个日期的行程的停留时间将大于 24:00:00。例如,如果行程从晚上 10:30:00 开始。并结束于 次日凌晨 2:15:00,停止时间为 22:30:00 和 26:15:00。将这些停止时间输入为 22:30:00 和 02:15:00 将 不会产生预期的结果。

如何停用我的 Time 对象的“验证”?我在 MySQL 查询中将时间字段写为 varchar 是 suggested,但我正在寻找一种不会让数据库干预的解决方案。

更新:关于保持 > 24:00 格式的相关性,使用该格式查询和 asc 排序所有 stop_times 以停止将返回如下内容:23:45、23:54、 24:35, 24:55, 25:15,这是下一辆公交车来的实际顺序。

反之则返回:0:35, 0:55, 1:15, 23:45, 23:54(这是错误的,前 3 个 stop_times 应该排在 之后 em> 最后 3)。

【问题讨论】:

    标签: ruby-on-rails ruby datetime activerecord


    【解决方案1】:

    您问题中的注释是在谈论 TimeDifference,而不是 Time 对象。

    我认为您应该将 TimeDifference 建模为数据库中的小数或浮点字段,其值等于以秒为单位的时间差。然后当您将其打印出来时,您可以将其重新格式化为 Days , 小时, 分钟。

    请注意,这是在 Ruby 中减去 Time 对象的方式:

    > t1 = Time.now
     => 2011-11-22 20:54:54 -0800 
    > t2 = Time.now.tomorrow
     => 2011-11-23 20:54:59 -0800 
    > t2 - t1
     => 86404.928009862    # these are seconds!  just store this in a float or decimal field
    > (t2 - t1).class
     => Float              # NOT a Time object
    

    尝试将时间差存储在时间对象或时间数据库字段中似乎是错误的。

    如果您从外部来源获得奇怪的输入值,例如 "26:12" ,最好将它们转换为秒数:

    hours,minutes = "26:12".split(/:/).map(&:to_i)
    seconds = hours * 3600 + minutes * 60
    

    ...然后以秒为单位存储时差


    哇,这来自 Google API?哎呀!!!

    不过,不要将它存储在 Time 对象中。

    你可以使用 divmod() 来清理:

     tomorrow,real_hour = hour.divmod(24)
    

    其中“明天”存储未来的天数,real_hour 是 24 小时制的有效值。

    如何为这些开始和停止时间创建一个单独的“TripTime”类,并拥有自己的属性:小时、分钟、天?航空公司通常将到达时间显示为“03:12 +1”.. 表示未来 +1 天。

    ... 或将那些奇怪的值存储为字符串,以保持排序顺序,并计算小时/分钟/秒的差异,然后您可以根据需要将它们转换为如上所示,splitmap

    【讨论】:

    • 我认为这确实有道理。在我的问题中添加了一些关于它的信息。
    • 对不起,我不明白你为什么说它在谈论时差。如果我按出发时间订购所有停止时间,我会看到类似 23:45、23:54、24:35、24:55、25:15 等
    • 为什么不把实际的Ruby Time对象存储为department_time和stop_time,先把这个BUGGY输入转换成有效的时间对象呢?
    • 因为这就是 GTFS 提要的分发方式; > 24:00 时间值。我想更改尽可能少的数据...
    • 添加了一些关于为什么这种时间格式有意义的附加信息。
    【解决方案2】:

    虽然@Tilo 是正确的,这可能不是最好的时间格式,但我不得不坚持使用它们,因此最终使用原始 SQL 将时间列转换为字符串:

    sql = "SELECT CONVERT(stop_time, CHAR) as stop_time from stop_times"
    stop_times = ActiveRecord::Base.connection.select_all sql
    time = stop_times[0]['stop_time'] # => returned as a string
    

    【讨论】:

      猜你喜欢
      • 2017-03-04
      • 2014-01-25
      • 2011-05-20
      • 2014-10-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多