2010-02-22 4 views

Répondre

140

Il peut être fait assez en utilisant de façon concise 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 

Vous pourriez probablement SEC davantage en obtenant créatif avec collect, ou inject peut-être, mais quand la logique de base est trois lignes, il peut être trop.

+0

Woodhouse @ Mike: c'est-ce que je cherchais. Je vous remercie. – Radek

+1

bonne réponse - merci. –

+0

+1, et si j'ai besoin de montrer les secondes jusqu'à 90 minutes par exemple Im suivre un jeu. ça devrait montrer quelque chose comme 90:54. Merci! – uday

9

Rails a un assistant qui convertit la distance du temps en mots. Vous pouvez regarder sa mise en œuvre: distance_of_time_in_words

+1

Existe-t-il un moyen de l'utiliser en dehors de Rails? – Kostas

+1

Oui. inclure ActionView :: Helpers :: DateHelper! –

+1

a = distance_of_time_in_words (FROM_TIME, FROM_TIME + 50.minutes) => "environ 1 heure" 1.9.2-p290: 035> –

13

J'espérais qu'il y aurait un moyen plus facile que d'utiliser divmod, mais c'est le plus sec et moyen réutilisable j'ai trouvé pour le faire:

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 

La méthode est facilement ajustée en changeant la chaîne de format et le premier tableau en ligne (ie [24,60,60]).

Version améliorée

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 

Exemples:

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" 

Notez que format_string ne vous laissera pas modifier l'ordre des parties (il est toujours la valeur la plus importante au moins). Pour un contrôle plus fin, vous pouvez utiliser split et manipuler les valeurs vous-même.

2

Je commence juste à écrire du rubis. Je suppose que cela est seulement pour 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

Si vous utilisez Rails, il existe un moyen facile si vous n'avez pas besoin de la précision:

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

merci de souligner que les rails a cette – nXqd

10

besoin d'une pause. Golfed cette place:

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

Vous pouvez utiliser la méthode la plus simple que j'ai trouvé à ce problème:

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 

Vous pouvez toujours ajuster la valeur retournée à vos besoins.

2.2.2 :062 > formatted_duration 3661 
=> "1 h 1 m 1 s" 
Questions connexes