У меня есть несколько секунд. Скажем, 270921. Как я могу отобразить это число, говорящее, что это xx days, yy hours, zz minutes, ww seconds?
Как конвертировать 270921сек в дни + часы + минуты + сек? (Рубин)
Ответ 1
Это можно сделать довольно кратко, используя 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
Возможно, вы, возможно, DRY, добавив креатив с collect
или, возможно, inject
, но когда основная логика состоит из трех строк, это может быть излишним.
Ответ 2
Я надеялся, что будет проще, чем использовать divmod, но это самый DRY и многоразовый способ, который я нашел для этого:
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
и сами управлять значениями.
Ответ 3
Необходим перерыв. В гольф это:
s = 270921
dhms = [60,60,24].reduce([s]) { |m,o| m.unshift(m.shift.divmod(o)).flatten }
# => [3, 3, 15, 21]
Ответ 4
У Rails есть помощник, который преобразует расстояние времени в словах. Вы можете посмотреть его реализацию: distance_of_time_in_words
Ответ 5
Если вы используете Rails, есть простой способ, если вам не нужна точность:
time_ago_in_words 270921.seconds.from_now
# => 3 days
Ответ 6
Вы можете использовать самый простой метод, который я нашел для этой проблемы:
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"
Ответ 7
Я только начинаю писать рубин. я предполагаю, что это только для 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