【问题标题】:Rails 5 how to save difference in hour and minutes between two datatime in postgres?Rails 5如何保存postgres中两个日期时间之间的小时和分钟差异?
【发布时间】:2017-12-24 18:40:11
【问题描述】:

我的表有 3 列:数据类型时间戳,

|created_At  |  final_time| duracion(difference between created at and final_time)
|            |            |

列差异应该保存小时和分钟的差异,格式为HH:MM

这是我的控制器:

def horario
  horario.update(duracion: params[:duracion]) // this params is "00:59"
end

但是在 Horarios 表中,在 duracion 列中我有这个:

2017-12-24 03:59:00 

所以我想保存 00:59(59 分钟),但 postgres 保存所有当前日期并增加 3 小时。 我想保存所以将来我将能够tu sum column duracion。或者我应该更改此列的数据类型?在这种情况下,您建议我使用哪种数据类型让 rails 保存 HH:MM??

谢谢。

【问题讨论】:

  • 你应该把它保存为字符串
  • @Jax,以后可以对它们求和吗?作为字符串?
  • PostgreSQL 支持标准 sql 区间数据类型。 Rails 不支持吗?
  • 不是,可以将字符串转换为时间进行进一步操作:Time.parse("00:59")
  • @MikeSherrill'CatRecall' 有部分支持,但由于 Ruby 中对无日期时间的支持有限,因此使用起来可能很麻烦。同样适用于标准 SQL times。

标签: ruby-on-rails postgresql rails-activerecord timestamp-with-timezone


【解决方案1】:

Rails 5 在一定程度上支持 PostgreSQL 的interval type。您可以按常规方式创建interval 列,它们将在db/schema.rb 中正确表示。你也可以用通常的方式给它们赋值,这样你就可以说:

model.some_interval = '6 hours'

并在数据库中获取06:00:00。但是,Ruby 或 Rails 中没有任何东西可以正确表示时间间隔(我们只有各种时间戳和日期类),因此当该间隔从数据库中出来时,您手上就会有一个字符串,即:

> model = Model.find(some_id)
> model.some_interval.class
 => String

因此您最终可能不得不在 Ruby 中手动解析一些字符串。对于像'6 hours' 这样的简单区间,这会很容易,但对于像'6 years 23 days 11 hours' 这样的更复杂的区间,就不会那么容易了。

如果您只在数据库中使用您的时间间隔,那么interval 将是自然而简单的,您可以这样说:

select some_timestamp + some_interval

where some_timestamp + some_interval < some_other_timestamp

一切都会很好。

但是,如果您需要在 Ruby 中使用间隔,那么您最好将间隔存储为整数列中的秒数(或您需要的任何分辨率)。然后你可以这样说:

where some_timestamp + (some_interval_in_seconds || 'seconds')::interval < some_other_timestamp

在数据库内部和

some_time + model.some_interval_in_seconds

回到 Ruby。

在任何情况下,字符串都可能是错误的方法,除非你真的喜欢随时随地解析字符串。

【讨论】:

    【解决方案2】:

    正如其他人已经指出的那样,Rails 将 Postgres Interval 类型作为字符串处理。不幸的是,一个不容易解析的字符串。

    如果你这样做:

    u = Users.select('edited_at - created_at as time_dif')
    puts u.first['time_dif']
    

    您可以获得类似168 days 12:51:20.851115 的信息。丑对不对?

    嗯,使用 Ruby 将此字符串转换为有用的数字并不容易,但您可以使用 Postgres 为您完成这项工作。虽然你需要做一个简单的 SQL 查询,但这是我迄今为止找到的最好的方法:

    query = ActiveRecord::Base.connection.execute("
      SELECT EXTRACT(epoch FROM time_dif)/3600 as hours_dif
      FROM
        (
          SELECT (edited_at - created_at) as time_dif
          FROM users
        ) AS MainQuery
    ")
    

    在本例中,Postgres 的EXTRACT function 会将 Interval 类型转换为一个数字,表示该间隔的总秒数。如果将此数字除以 3600,您将得到不同的小时数,如上例所示。

    那么,如果你想遍历结果:

    query.each do |r|
      puts r['hours_dif']
    end
    

    【讨论】:

      【解决方案3】:

      您可以将duracion 保存为浮点类型,其中duracion 将等于final_time - created_at 之类的值,该值将以秒为单位。然后,您可以使用这些值执行算术运算,并始终转换回分钟、小时或任何您需要的值。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-01-17
        • 1970-01-01
        • 2013-05-14
        • 2012-10-26
        • 1970-01-01
        相关资源
        最近更新 更多