2010-02-22 19 views

risposta

140

Esso può essere fatto abbastanza conciso utilizzando 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 

Si potrebbe probabilmente asciugare ulteriormente ottenendo creativo con collect, o forse inject, ma quando la logica di base è tre linee potrebbe essere eccessivo.

+0

@ Mike Woodhouse: questo è quello che stavo cercando. Grazie. – Radek

+1

ottima risposta - grazie. –

+0

+1, Cosa succede se ho bisogno di mostrare i secondi fino a 90 minuti, ad esempio Im monitoraggio di un gioco. dovrebbe mostrare qualcosa come 90:54. Grazie! – uday

9

Rails ha un helper che converte la distanza del tempo in parole. Si può guardare la sua attuazione: distance_of_time_in_words

+1

C'è un modo per usarlo al di fuori di Rails? – Kostas

+1

Sì. include ActionView :: Helpers :: DateHelper! –

+1

a = distance_of_time_in_words (from_time, from_time + 50.minutes) => "circa 1 ora" 1.9.2-p290: 035> –

13

Speravo ci sarebbe un modo più semplice che usare divmod, ma questo è il modo più DRY e riutilizzabile ho trovato per farlo:

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 

Il metodo è facilmente regolabile modificando la stringa di formato e il primo array inline (cioè [24,60,60]).

versione migliorata

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 

Esempi:

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" 

Nota che format_string non ti consente di cambiare l'ordine delle parti (è sempre il valore più significativo al meno). Per un controllo a grana fine, puoi usare split e manipolare i valori tu stesso.

2

Ho appena iniziato a scrivere rubino. Credo che questo è solo per 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

Se stai usando Rails, c'è un modo semplice, se non è necessario la precisione:

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

grazie per aver sottolineato che le rotaie hanno questo – nXqd

10

bisogno di una pausa. Golfed questo in su:

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

È possibile utilizzare il metodo più semplice che ho trovato per questo problema:

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 

È sempre possibile regolare valore restituito alle proprie esigenze.

2.2.2 :062 > formatted_duration 3661 
=> "1 h 1 m 1 s" 
Problemi correlati