在Rails 3或Ruby中将持续时间转换为小时:分钟:秒(或类似)


114

我感觉有一种简单/内置的方法可以执行此操作,但我找不到它。

我有一个以整数表示的持续时间(以秒为单位),我想以一种友好的格式显示它。

例如3600将显示为“ 01:00:00”或“ 1小时”或其他内容。

我可以做到这一点,time_ago_in_words(Time.zone.now+3600)但是感觉有点像破解,没有理由在当前时间添加/减去仅用于格式化此值。有duration_in_words()东西吗?

谢谢

Answers:


82

请参阅:http : //api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html

distance_of_time_in_words(3600)
 => "about 1 hour"

1
谢谢,我看着那个,但以为我必须提供两次。。
cydonia 2010年

1
是的,这些例子都是愚蠢的
艾伦(Allan)2010年

1
distance_of_time_in_words(from_time,to_time,...)
boulder_ruby 2012年

1
另外,如果您想让它非常具体而不是“持续时间”,请查看Radar的瑰宝:github.com/radar/distance_of_time_in_words。直接替换distance_of_time_in_words,您可以通过vague: true作为选项传递舍入的数字。
约书亚·品特

194

加起来:

假如说 total_seconds = 3600

选项1:

distance_of_time_in_words(total_seconds) #=> "about 1 hour"

选项2:

Time.at(total_seconds).utc.strftime("%H:%M:%S") #=> "01:00:00"

选项3:

seconds = total_seconds % 60
minutes = (total_seconds / 60) % 60
hours = total_seconds / (60 * 60)

format("%02d:%02d:%02d", hours, minutes, seconds) #=> "01:00:00"

如果您要输入文字,请使用Option1;如果您要使用H:M:S格式,请使用Option2;如果您要使用H:M:S格式,请使用Option3,并且可能会超过24小时


1
distance_of_time_in_words方法是一个ActionView帮助器,因此需要从View(而不是控制器)中调用。 api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html
msdundar 2014年

13
请注意,strftime选项将在24小时溢出。如果持续时间为25小时,则将显示01:00:00
·马丁·丹佩西

2
这在负时间不起作用,例如-1800返回-1h 30m而不是-30m
Arnold Roa

43

Ruby的字符串%运算符太过被人们所理解和忘记了。

"%02d:%02d:%02d:%02d" % [t/86400, t/3600%24, t/60%60, t%60]

给定t是一个持续时间(以秒为单位),它将发出一个零填充的冒号分隔的字符串(包括天)。例:

t = 123456
"%02d:%02d:%02d:%02d" % [t/86400, t/3600%24, t/60%60, t%60]
=> "01:10:17:36"

可爱。


24
那是“可爱”的奇怪定义。
马克·布林格

10
这样%说:“从我的右边获取参数数组,并将其插入到我的左边的格式字符串中。” 在这方面,它printf更简洁地类似于C \ C ++,并且可以在分配中使用。是的,我称之为可爱。而且功能强大。有一些例子可以更好地证明这种口才,但是他们不能回答这个问题。顺便说一句,您的蛇ark不被感激。
IAmNaN 2015年

26

我想您也可以执行以下操作:

(Time.mktime(0)+3600).strftime("%H:%M:%S")

格式化它,如你所愿。

顺便说一句,最初我想使用Time.at(),但是在我的Ubuntu上,EPOCH时间是Thu Jan 01 01:00:00 +0100 1970,而不是我期望的00:00:00小时,因此如果我这样做:

Time.at(3600).strftime("%H:%M:%S")

给我比希望多1小时的时间。


嗯,可能是因为夏天而要做些事情吗?
Cristobal Viedma

7
唯一要注意的是,如果您要处理的时间超过24小时。在这种情况下,小时数会回落到很少的数目。
metavida 2011年

对于大于24小时的时间,%j将为您提供天数(只要少于365天)
BananaNeil 2014年

17

我用它来显示我的Rails项目中的持续时间:

  1. 将自定义方法添加到Integer类。您可以pretty_duration.rbinitializers文件夹中创建一个名为的新文件:

    class Integer
        def pretty_duration
            parse_string = 
                if self < 3600
                    '%M:%S'
                else
                    '%H:%M:%S'
                end
    
            Time.at(self).utc.strftime(parse_string)
        end
    end
  2. seconds.pretty_duration在项目中的任何地方调用:

    275.pretty_duration     # => "04:35"
    9823.pretty_duration    # => "02:43:43"

这个答案建立在列夫·卢科姆斯基的密码上


很棒。这次真是万分感谢。
唐·费尔克

13

这是一种使用模糊divmod方法同时进行除法和求模的方法,因此它可以Float正确处理秒数:

def duration(seconds)
  minutes, seconds = seconds.divmod(60)
  hours, minutes = minutes.divmod(60)
  days, hours = hours.divmod(24)

  "#{days.to_s.rjust(3)}d #{hours.to_s.rjust(2)}h #{minutes.to_s.rjust(2)}m #{seconds}s"
end

6

Time.utc.strftime当总小时数少于24小时时,仅对值使用:

2.2.2 :004 > Time.at(60 * 60).utc.strftime('%H h %M m')
=> "01 h 00 m"

对于更大的值,它返回错误的结果:

2.2.2 :006 > Time.at(60 * 60 * 24).utc.strftime('%H h %M m')
 => "00 h 00 m"

我建议使用我发现的最简单的方法来解决此问题:

  def formatted_duration total_seconds
    hours = total_seconds / (60 * 60)
    minutes = (total_seconds / 60) % 60
    seconds = total_seconds % 60
    "#{ hours } h #{ minutes } m #{ seconds } s"
  end

您始终可以根据需要调整返回值。


5

持续时间超过一天要小心。

(timing/3600).to_i.to_s.rjust(2,'0') + ":"+Time.at(timing).utc.strftime("%M:%S")

举一个输入/输出示例,重点介绍如何解决
极端

4

列夫·卢科姆斯基(Lev Lukomsky)利用ActiveSupport :: Duration并处理毫秒(对基准代码有用)得出的答案

# duration in ms modulus number of ms in one second
milliseconds = duration.in_milliseconds % 1.second.in_milliseconds

# duration in seconds modulus number of seconds in one minute
seconds = (duration / 1.second) % (1.minute / 1.second)

# duration in minutes modulus number of minutes in one hour
minutes = (duration / 1.minute) % (1.hour / 1.minute)

# duration in hours modulus number of hours in one day
hours = (duration / 1.hour) % (1.day / 1.hour)

format("%02d:%02d:%02d:%03d", hours, minutes, seconds, milliseconds) #=> "12:05:00:001"

当然,您可以使用相关的ActiveSupport方法并重复相同的结构,轻松地将其扩展为几天,几个月,几年等。

请记住,由于持续时间太长,这可能是不准确的,因为1个月的持续时间不是固定的天数,而且我不确定AS:Duration如何处理该时间。


2

只需投入我的2美分:

Time.at(i).utc.strftime((i < 3600) ? '%-M minutes and %-S seconds' : '%-H hours, %-M minutes, and %-S seconds')

建立在小斌的答案之上。


2

@joshuapinter喊出最好的答案(以评论的形式)。

使用嵌入式替换dotiwgem可以更好地控制输出的精度,以满足不同的需求:

https://github.com/radar/distance_of_time_in_words

示例查看代码:

%label
  Logoff after:
  - expire_in = distance_of_time_in_words(Time.now, Time.now + user.custom_timeout.minutes, :only => [:minutes, :hours, :days])
  = expire_in

结果是这样的:

Logoff after: 1 day, 13 hours, and 20 minutes

2

ActiveSupport::Duration.build+ inspect给您有效的结果

 >> ActiveSupport::Duration.build(125557).inspect
 => "1 day, 10 hours, 52 minutes, and 37 seconds"

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.