J'ai quelques secondes. Disons 270921. Comment puis-je afficher ce nombre en indiquant qu'il s'agit de xx jours, aa heures, zz minutes, secondes?
Cela peut être fait de manière assez concise en utilisant 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 DRY continuer plus loin en faisant preuve de créativité avec collect
, ou peut-être inject
, mais lorsque la logique de base est composée de trois lignes, il peut être excessif.
J'espérais qu'il y aurait un moyen plus facile que d'utiliser divmod, mais c'est le moyen le plus DRY et le plus réutilisable que 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 modifiant la chaîne de formatage et le premier tableau en ligne (c'est-à-dire le [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 changer l'ordre des pièces (c'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.
Besoin d'une pause. Golfé cette place:
s = 270921
dhms = [60,60,24].reduce([s]) { |m,o| m.unshift(m.shift.divmod(o)).flatten }
# => [3, 3, 15, 21]
Rails a un assistant qui convertit la distance de temps en mots . Vous pouvez regarder son implémentation: distance_du_temps_en_mots
Si vous utilisez Rails, il existe un moyen simple de ne pas avoir besoin de précision:
time_ago_in_words 270921.seconds.from_now
# => 3 days
Vous pouvez utiliser la méthode la plus simple que j'ai trouvée pour résoudre 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 renvoyée à vos besoins.
2.2.2 :062 > formatted_duration 3661
=> "1 h 1 m 1 s"
Je commence juste à écrire Ruby. Je suppose que ce n'est que 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
J'ai modifié la réponse donnée par @Mike pour ajouter un formatage dynamique basé sur la taille du résultat.
def formatted_duration(total_seconds)
dhms = [60, 60, 24].reduce([total_seconds]) { |m,o| m.unshift(m.shift.divmod(o)).flatten }
return "%d days %d hours %d minutes %d seconds" % dhms unless dhms[0].zero?
return "%d hours %d minutes %d seconds" % dhms[1..3] unless dhms[1].zero?
return "%d minutes %d seconds" % dhms[2..3] unless dhms[2].zero?
"%d seconds" % dhms[3]
end