I'm looking for the best way to use a duration field in a Rails model. I would like the format to be HH:MM:SS (ex: 01:30:23). The database in use is sqlite locally and Postgres in production.
我正在寻找在Rails模型中使用持续时间字段的最佳方法。我希望格式是HH:MM:SS(例:01:30:23)。正在使用的数据库是本地的sqlite和生产中的Postgres。
I would also like to work with this field so I can take a look at all of the objects in the field and come up with the total time of all objects in that model and end up with something like:
我也想研究这个领域,这样我就可以看看这个领域中的所有对象然后得出模型中所有对象的总时间最后得到如下结果:
30 records totaling 45 hours, 25 minutes, and 34 seconds.
总共45小时25分钟34秒的30项记录。
So what would work best for?
那么,什么才是最有效的呢?
- Field type for the migration
- 迁移的字段类型
- Form field for the CRUD forms (hour, minute, second drop downs?)
- CRUD表单的表单字段(小时,分钟,第二次下降?)
- Least expensive method to generate the total duration of all records in the model
- 生成模型中所有记录的总持续时间的最便宜方法
4 个解决方案
#1
41
- Store as integers in your database (number of seconds, probably).
- 以整数形式存储在数据库中(可能是秒数)。
- Your entry form will depend on the exact use case. Dropdowns are painful; better to use small text fields for duration in hours + minutes + seconds.
- 您的输入表单将取决于确切的用例。下拉是痛苦的;最好使用小文本字段,持续时间为小时+分钟+秒。
- Simply run a
SUM
query over the duration column to produce a grand total. If you use integers, this is easy and fast. - 只需在duration列上运行SUM查询,生成一个总计。如果您使用整数,这是容易和快速的。
Additionally:
另外:
- Use a helper to display the duration in your views. You can easily convert a duration as integer of seconds to
ActiveSupport::Duration
by using123.seconds
(replace123
with the integer from the database). Useinspect
on the resultingDuration
for nice formatting. (It is not perfect. You may want to write something yourself.) - 使用助手在视图中显示持续时间。通过使用123,您可以轻松地将持续时间转换为秒的整数,并将其转换为ActiveSupport:: duration。秒(用数据库中的整数替换123)。使用查看结果的持续时间进行漂亮的格式化。(它并不完美。你可能想自己写点东西。
- In your model, you'll probably want attribute readers and writers that return/take
ActiveSupport::Duration
objects, rather than integers. Simply defineduration=(new_duration)
andduration
, which internally callread_attribute
/write_attribute
with integer arguments. - 在您的模型中,您可能希望属性读取器和写入器返回/执行ActiveSupport::Duration对象,而不是整数。简单地定义duration=(new_duration)和duration,在内部调用read_attribute / write_attribute具有整型参数。
#2
6
In Rails 5, you can use ActiveRecord::Attributes to store ActiveSupport::Durations as ISO8601 strings. The advantage of using ActiveSupport::Duration over integers is that you can use them for date/time calculations right out of the box. You can do things like Time.now + 1.month
and it's always correct.
在Rails 5中,您可以使用ActiveRecord:属性来存储ActiveSupport::Durations作为ISO8601字符串。使用ActiveSupport::持续时间超过整数的优点是您可以使用它们进行日期/时间计算。你可以做一些事情,比如时间。现在+ 1。每个月都是正确的。
Here's how:
方法如下:
Add config/initializers/duration_type.rb
添加配置/初始化/ duration_type.rb
class DurationType < ActiveRecord::Type::String
def cast(value)
return value if value.blank? || value.is_a?(ActiveSupport::Duration)
ActiveSupport::Duration.parse(value)
end
def serialize(duration)
duration ? duration.iso8601 : nil
end
end
ActiveRecord::Type.register(:duration, DurationType)
Migration
迁移
create_table :somethings do |t|
t.string :duration
end
Model
模型
class Something < ApplicationRecord
attribute :duration, :duration
end
Usage
使用
something = Something.new
something.duration = 1.year # 1 year
something.duration = nil
something.duration = "P2M3D" # 2 months, 3 days (ISO8601 string)
Time.now + something.duration # calculation is always correct
#3
5
I tried using ActiveSupport::Duration but had trouble getting the output to be clear.
我尝试使用ActiveSupport::持续时间,但很难让输出变得清晰。
You may like ruby-duration, an immutable type that represents some amount of time with accuracy in seconds. It has lots of tests and a Mongoid model field type.
您可能喜欢ruby-duration,一种不变的类型,它表示以秒为单位的时间。它有许多测试和Mongoid模型字段类型。
I wanted to also easily parse human duration strings so I went with Chronic Duration. Here's an example of adding it to a model that has a time_spent in seconds field.
我还想简单地解析人工持续时间字符串,所以我选择了慢性持续时间。这里有一个将它添加到具有在seconds字段中花费时间的模型的示例。
class Completion < ActiveRecord::Base
belongs_to :task
belongs_to :user
def time_spent_text
ChronicDuration.output time_spent
end
def time_spent_text= text
self.time_spent = ChronicDuration.parse text
logger.debug "time_spent: '#{self.time_spent_text}' for text '#{text}'"
end
end
#4
3
I've wrote a some stub to support and use PostgreSQL's interval
type as ActiveRecord::Duration
.
我编写了一个存根来支持和使用PostgreSQL的interval类型作为ActiveRecord: Duration。
See this gist (you can use it as initializer in Rails 4.1): https://gist.github.com/Envek/7077bfc36b17233f60ad
参见这个要点(您可以在Rails 4.1中使用它作为初始化器):https://gist.github.com/Envek/7077bfc36b17233f60ad
Also I've opened pull requests to the Rails there: https://github.com/rails/rails/pull/16919
我还打开了对那里的Rails的拉请求:https://github.com/rails/rails/pulls/16919
#1
41
- Store as integers in your database (number of seconds, probably).
- 以整数形式存储在数据库中(可能是秒数)。
- Your entry form will depend on the exact use case. Dropdowns are painful; better to use small text fields for duration in hours + minutes + seconds.
- 您的输入表单将取决于确切的用例。下拉是痛苦的;最好使用小文本字段,持续时间为小时+分钟+秒。
- Simply run a
SUM
query over the duration column to produce a grand total. If you use integers, this is easy and fast. - 只需在duration列上运行SUM查询,生成一个总计。如果您使用整数,这是容易和快速的。
Additionally:
另外:
- Use a helper to display the duration in your views. You can easily convert a duration as integer of seconds to
ActiveSupport::Duration
by using123.seconds
(replace123
with the integer from the database). Useinspect
on the resultingDuration
for nice formatting. (It is not perfect. You may want to write something yourself.) - 使用助手在视图中显示持续时间。通过使用123,您可以轻松地将持续时间转换为秒的整数,并将其转换为ActiveSupport:: duration。秒(用数据库中的整数替换123)。使用查看结果的持续时间进行漂亮的格式化。(它并不完美。你可能想自己写点东西。
- In your model, you'll probably want attribute readers and writers that return/take
ActiveSupport::Duration
objects, rather than integers. Simply defineduration=(new_duration)
andduration
, which internally callread_attribute
/write_attribute
with integer arguments. - 在您的模型中,您可能希望属性读取器和写入器返回/执行ActiveSupport::Duration对象,而不是整数。简单地定义duration=(new_duration)和duration,在内部调用read_attribute / write_attribute具有整型参数。
#2
6
In Rails 5, you can use ActiveRecord::Attributes to store ActiveSupport::Durations as ISO8601 strings. The advantage of using ActiveSupport::Duration over integers is that you can use them for date/time calculations right out of the box. You can do things like Time.now + 1.month
and it's always correct.
在Rails 5中,您可以使用ActiveRecord:属性来存储ActiveSupport::Durations作为ISO8601字符串。使用ActiveSupport::持续时间超过整数的优点是您可以使用它们进行日期/时间计算。你可以做一些事情,比如时间。现在+ 1。每个月都是正确的。
Here's how:
方法如下:
Add config/initializers/duration_type.rb
添加配置/初始化/ duration_type.rb
class DurationType < ActiveRecord::Type::String
def cast(value)
return value if value.blank? || value.is_a?(ActiveSupport::Duration)
ActiveSupport::Duration.parse(value)
end
def serialize(duration)
duration ? duration.iso8601 : nil
end
end
ActiveRecord::Type.register(:duration, DurationType)
Migration
迁移
create_table :somethings do |t|
t.string :duration
end
Model
模型
class Something < ApplicationRecord
attribute :duration, :duration
end
Usage
使用
something = Something.new
something.duration = 1.year # 1 year
something.duration = nil
something.duration = "P2M3D" # 2 months, 3 days (ISO8601 string)
Time.now + something.duration # calculation is always correct
#3
5
I tried using ActiveSupport::Duration but had trouble getting the output to be clear.
我尝试使用ActiveSupport::持续时间,但很难让输出变得清晰。
You may like ruby-duration, an immutable type that represents some amount of time with accuracy in seconds. It has lots of tests and a Mongoid model field type.
您可能喜欢ruby-duration,一种不变的类型,它表示以秒为单位的时间。它有许多测试和Mongoid模型字段类型。
I wanted to also easily parse human duration strings so I went with Chronic Duration. Here's an example of adding it to a model that has a time_spent in seconds field.
我还想简单地解析人工持续时间字符串,所以我选择了慢性持续时间。这里有一个将它添加到具有在seconds字段中花费时间的模型的示例。
class Completion < ActiveRecord::Base
belongs_to :task
belongs_to :user
def time_spent_text
ChronicDuration.output time_spent
end
def time_spent_text= text
self.time_spent = ChronicDuration.parse text
logger.debug "time_spent: '#{self.time_spent_text}' for text '#{text}'"
end
end
#4
3
I've wrote a some stub to support and use PostgreSQL's interval
type as ActiveRecord::Duration
.
我编写了一个存根来支持和使用PostgreSQL的interval类型作为ActiveRecord: Duration。
See this gist (you can use it as initializer in Rails 4.1): https://gist.github.com/Envek/7077bfc36b17233f60ad
参见这个要点(您可以在Rails 4.1中使用它作为初始化器):https://gist.github.com/Envek/7077bfc36b17233f60ad
Also I've opened pull requests to the Rails there: https://github.com/rails/rails/pull/16919
我还打开了对那里的Rails的拉请求:https://github.com/rails/rails/pulls/16919