2010-02-22 144 views

回答

140

可以非常做到簡明使用divmod

t = 270921 
mm, ss = t.divmod(60)   #=> [4515, 21] 
hh, mm = mm.divmod(60)   #=> [75, 15] 
dd, hh = hh.divmod(24)   #=> [3, 3] 
puts "%d days, %d hours, %d minutes and %d seconds" % [dd, hh, mm, ss] 
#=> 3 days, 3 hours, 15 minutes and 21 seconds 

你也許可以通過讓創意與collect,也許inject進一步乾燥,但是當核心邏輯是三條線可能會矯枉過正。

+0

@Mike Woodhouse:那就是我一直在尋找的東西。謝謝。 – Radek 2010-02-22 20:18:21

+1

偉大的答案 - 謝謝。 – 2012-09-20 07:00:58

+0

+1,如果我需要顯示秒數直到90分鐘,例如我在跟蹤一個遊戲。它應該顯示90:54。謝謝! – uday 2012-10-08 23:38:12

9

Rails有一個幫手,可以用單詞轉換時間的距離。 你可以看看它的實現:distance_of_time_in_words

+1

有沒有辦法在Rails之外使用它? – Kostas 2011-06-12 13:33:02

+1

是的。包括ActionView :: Helpers :: DateHelper! – 2012-03-05 20:50:25

+1

a = distance_of_time_in_words(from_time,from_time + 50.minutes) =>「大約1小時」 1.9.2-p290:035> – 2012-03-05 20:50:34

13

我希望會有比使用divmod更簡單的方法,但是這是最乾燥,可重複使用的方式,我發現做到這一點:

def seconds_to_units(seconds) 
    '%d days, %d hours, %d minutes, %d seconds' % 
    # the .reverse lets us put the larger units first for readability 
    [24,60,60].reverse.inject([seconds]) {|result, unitsize| 
     result[0,0] = result.shift.divmod(unitsize) 
     result 
    } 
end 

的方法很容易被改變的格式字符串調整第一個內聯數組(即[24,60,60])。

增強版本

class TieredUnitFormatter 
    # if you set this, '%d' must appear as many times as there are units 
    attr_accessor :format_string 

    def initialize(unit_names=%w(days hours minutes seconds), conversion_factors=[24, 60, 60]) 
    @unit_names = unit_names 
    @factors = conversion_factors 

    @format_string = unit_names.map {|name| "%d #{name}" }.join(', ') 
    # the .reverse helps us iterate more effectively 
    @reversed_factors = @factors.reverse 
    end 

    # e.g. seconds 
    def format(smallest_unit_amount) 
    parts = split(smallest_unit_amount) 
    @format_string % parts 
    end 

    def split(smallest_unit_amount) 
    # go from smallest to largest unit 
    @reversed_factors.inject([smallest_unit_amount]) {|result, unitsize| 
     # Remove the most significant item (left side), convert it, then 
     # add the 2-element array to the left side of the result. 
     result[0,0] = result.shift.divmod(unitsize) 
     result 
    } 
    end 
end 

例子:

fmt = TieredUnitFormatter.new 
fmt.format(270921) # => "3 days, 3 hours, 15 minutes, 21 seconds" 

fmt = TieredUnitFormatter.new(%w(minutes seconds), [60]) 
fmt.format(5454) # => "90 minutes, 54 seconds" 
fmt.format_string = '%d:%d' 
fmt.format(5454) # => "90:54" 

注意format_string不會讓你改變部分的順序(它總是最顯著值到最低)。對於更細粒度的控制,您可以使用split並自己操作這些值。

2

我剛開始寫紅寶石。我想這是隻爲1.9.3

def dateBeautify(t) 

    cute_date=Array.new 
    tables=[ ["day", 24*60*60], ["hour", 60*60], ["minute", 60], ["sec", 1] ] 

    tables.each do |unit, value| 
     o = t.divmod(value) 
     p_unit = o[0] > 1 ? unit.pluralize : unit 
     cute_date.push("#{o[0]} #{unit}") unless o[0] == 0 
     t = o[1] 
    end 
    return cute_date.join(', ') 

end 
9

如果您使用Rails的,還有就是如果你不需要精密的簡單方法:

time_ago_in_words 270921.seconds.from_now 
# => 3 days 
+0

感謝您指出rails有這個 – nXqd 2014-09-15 18:16:02

10

需要休息。 Golfed這件事:

s = 270921 
dhms = [60,60,24].reduce([s]) { |m,o| m.unshift(m.shift.divmod(o)).flatten } 
# => [3, 3, 15, 21] 
4

您可以使用,我發現這個問題最簡單的方法:

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 

您可以隨時調整返回的值您的需求。

2.2.2 :062 > formatted_duration 3661 
=> "1 h 1 m 1 s" 
相關問題