ruby - for - cómo convertir 270921sec en días+horas+minutos+segundo?(rubí)
ruby puts date time (8)
Tengo una cantidad de segundos. Digamos 270921. ¿Cómo puedo mostrar ese número diciendo que es xx días, aa horas, zz minutos, segundos ww?
Esperaba que hubiera una manera más fácil que utilizar DivDod, pero esta es la manera más SECA y reutilizable que he encontrado para hacerlo:
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
El método se ajusta fácilmente cambiando la cadena de formato y la primera matriz en línea (es decir, la [24,60,60]).
Versión mejorada
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
Ejemplos:
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"
Tenga en cuenta que format_string
no le permitirá cambiar el orden de las partes (siempre es el valor más significativo al menos). Para un control más detallado, puede usar split
y manipular los valores usted mismo.
Modifiqué la respuesta dada por @Mike para agregar formato dinámico basado en el tamaño del resultado
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
Necesitó un descanso. Golfed esto:
s = 270921
dhms = [60,60,24].reduce([s]) { |m,o| m.unshift(m.shift.divmod(o)).flatten }
# => [3, 3, 15, 21]
Puedes usar el método más simple que encontré para este 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
Siempre puede ajustar el valor devuelto a sus necesidades.
2.2.2 :062 > formatted_duration 3661
=> "1 h 1 m 1 s"
Rails tiene un helper que convierte la distancia de tiempo en palabras. Puede ver su implementación: distance_of_time_in_words
Si está utilizando Rails, hay una manera fácil de hacerlo si no necesita la precisión:
time_ago_in_words 270921.seconds.from_now
# => 3 days
Solo empiezo a escribir Ruby. Supongo que esto es solo para 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
Se puede hacer de manera muy concisa usando 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
Probablemente podrías DIBUJARLO más al ser creativo con la collect
, o tal vez inject
, pero cuando la lógica central es de tres líneas, puede ser exagerado.