Перетворіть тривалість на години: хвилини: секунди (або подібні) в Rails 3 або Ruby


115

У мене є відчуття, що для цього є простий / вбудований спосіб, але я не можу його знайти.

У мене тривалість (у секундах) ціле число, і я хочу відобразити це у дружньому форматі.

наприклад, 3600 відображатиметься як "01:00:00" або "1 година" або щось подібне.

Я можу це зробити, time_ago_in_words(Time.zone.now+3600)але це виглядає як би злом, немає причин додавати / віднімати з поточного часу просто для форматування цього значення. Є duration_in_words()чи щось?

Дякую

Відповіді:


83

Дивіться: http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html

distance_of_time_in_words(3600)
 => "about 1 hour"

1
дякую, що я подивився на це, але подумав, що мені довелося надати два рази .. яка нуб!
цидонія

1
так, ці приклади дафф
Аллан

1
distance_of_time_in_words (from_time, to_time, ...)
boulder_ruby

1
Крім того, якщо ви хочете, щоб це було дуже конкретним і не "круглим" тривалістю, перегляньте дорогоцінний камінь Radar: github.com/radar/distance_of_time_in_words . Заміна, що випадає, distance_of_time_in_wordsі округлене число ви можете отримати, перейшовши vague: trueяк опцію.
Джошуа Пінтер

194

Підводячи підсумки:

припускаючи, що total_seconds = 3600

Варіант 1:

distance_of_time_in_words(total_seconds) #=> "about 1 hour"

Варіант 2:

Time.at(total_seconds).utc.strftime("%H:%M:%S") #=> "01:00:00"

Варіант 3:

seconds = total_seconds % 60
minutes = (total_seconds / 60) % 60
hours = total_seconds / (60 * 60)

format("%02d:%02d:%02d", hours, minutes, seconds) #=> "01:00:00"

використовуйте Option1, якщо ви хочете слова, Варіант2, якщо ви хочете формат H: M: S, Варіант3 якщо ви хочете формату H: M: S, і може бути більше 24 годин


1
Метод distance_of_time_in_words є помічником ActionView, тому його потрібно викликати з виду (а не контролера). api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html
msdundar

13
Зауважте, що опція стринглінгу переповниться через 24 години. Якщо ваша тривалість 25 годин, вона відобразиться 01:00:00.
Гейб Мартін-Демпесі

2
це не працює в негативні часи, наприклад -1800 повертається -1 год 30 м замість -30 м.
Арнольд Роа

44

Струнний %оператор Рубі занадто недооцінений і часто забутий.

"%02d:%02d:%02d:%02d" % [t/86400, t/3600%24, t/60%60, t%60]

Враховуючи, що t - тривалість у секундах, це випромінює нульову колонку, розділену двокрапкою, включаючи дні. Приклад:

t = 123456
"%02d:%02d:%02d:%02d" % [t/86400, t/3600%24, t/60%60, t%60]
=> "01:10:17:36"

Прекрасна.


24
Це дивне визначення "чудового".
Марк Боллінгер

10
%Каже: «Візьміть масив параметрів з мого права і вставити їх в рядок формату зліва від мене.» У цьому відношенні він схожий на printfC \ C ++ лише більш стислим і може бути використаний у призначенні. Так, я називаю це прекрасно. І потужний. Є приклади, які б краще продемонстрували це красномовство, але вони не відповіли б на це питання. Твого змія не цінують, дощо.
IAmNaN

26

Я думаю, ви можете зробити також щось на кшталт:

(Time.mktime(0)+3600).strftime("%H:%M:%S")

Відформатувати його за бажанням.

BTW, спочатку я думав про використання Time.at (), але здається, що час EPOCH на моєму Ubuntu - це Четвер 01 січня 01:00:00 +0100 1970, а не 00:00:00 годин, як я очікував, і тому, якщо це робити:

Time.at(3600).strftime("%H:%M:%S")

Дає мені на 1 годину більше, ніж хотілося.


ах, може щось зробити через літній час?
Крістобаль Вієдма

7
Єдина уловка, якщо ви маєте справу з часом більше 24 годин. У такому випадку години повернуться до низької кількості.
metavida

У рази більше, ніж 24 години,% j дасть вам кількість днів (поки вона менше 365)
BananaNeil

18

Я використовую це для показу тривалості часу в моєму проекті Rails:

  1. Додайте спеціальний метод до Integerкласу. Ви можете створити новий файл, який називається pretty_duration.rbу initializersпапці:

    class Integer
        def pretty_duration
            parse_string = 
                if self < 3600
                    '%M:%S'
                else
                    '%H:%M:%S'
                end
    
            Time.at(self).utc.strftime(parse_string)
        end
    end
  2. Телефонуйте в seconds.pretty_durationбудь-який момент вашого проекту:

    275.pretty_duration     # => "04:35"
    9823.pretty_duration    # => "02:43:43"

Ця відповідь ґрунтується на Кодексі Лева Лукомського


Працювали чудово. Дякую за це.
Донн Фелкер

13

Цей divmodметод використовує незрозумілий метод поділу та модуля одночасно, тому він обробляє Floatсекунди належним чином:

def duration(seconds)
  minutes, seconds = seconds.divmod(60)
  hours, minutes = minutes.divmod(60)
  days, hours = hours.divmod(24)

  "#{days.to_s.rjust(3)}d #{hours.to_s.rjust(2)}h #{minutes.to_s.rjust(2)}m #{seconds}s"
end

6

Використання Time.utc.strftimeробіт лише для значень, коли загальна кількість годин менше 24 :

2.2.2 :004 > Time.at(60 * 60).utc.strftime('%H h %M m')
=> "01 h 00 m"

Для більших значень він повертає неправильні результати:

2.2.2 :006 > Time.at(60 * 60 * 24).utc.strftime('%H h %M m')
 => "00 h 00 m"

Я пропоную використовувати найпростіший метод, який я знайшов для цієї проблеми:

  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

Ви завжди можете налаштувати повернене значення під свої потреби.


5

Будьте обережні з тривалістю більше одного дня.

(timing/3600).to_i.to_s.rjust(2,'0') + ":"+Time.at(timing).utc.strftime("%M:%S")

Наведіть приклад введення / виводу, підкреслюючи, як це вирішує кутовий випадок
Кирило Дюшон-Доріс

4

Відповідь, натхненна тим, що Лев Лукомський використовував ActiveSupport :: Тривалість та обробку мілісекунд (корисно для порівняльного коду)

# duration in ms modulus number of ms in one second
milliseconds = duration.in_milliseconds % 1.second.in_milliseconds

# duration in seconds modulus number of seconds in one minute
seconds = (duration / 1.second) % (1.minute / 1.second)

# duration in minutes modulus number of minutes in one hour
minutes = (duration / 1.minute) % (1.hour / 1.minute)

# duration in hours modulus number of hours in one day
hours = (duration / 1.hour) % (1.day / 1.hour)

format("%02d:%02d:%02d:%03d", hours, minutes, seconds, milliseconds) #=> "12:05:00:001"

Звичайно, ви можете продовжити це легко днями, місяцями, роками тощо, використовуючи відповідні методи ActiveSupport та повторюючи ту саму структуру.

Майте на увазі, що для занадто тривалої тривалості це може бути неточним, оскільки тривалість 1 місяць не фіксується в кількості днів, і я не впевнений, як AS: Тривалість вирішує це.


2

Просто, щоб кинути мої 2 копійки:

Time.at(i).utc.strftime((i < 3600) ? '%-M minutes and %-S seconds' : '%-H hours, %-M minutes, and %-S seconds')

Побудований з відповіді Сяо Біна.


2

Вигукніть на @joshuapinter, який дав найкращу відповідь (у формі коментаря ).

Використовуйте заміну, що випадає dotiw коштовний камінь для щоб отримати більше контролю над точністю виходу, щоб задовольнити різні потреби:

https://github.com/radar/distance_of_time_in_words

Приклад коду перегляду:

%label
  Logoff after:
  - expire_in = distance_of_time_in_words(Time.now, Time.now + user.custom_timeout.minutes, :only => [:minutes, :hours, :days])
  = expire_in

Отримавши щось подібне:

Logoff after: 1 day, 13 hours, and 20 minutes

2

ActiveSupport::Duration.build+ inspectдає вагомі результати

 >> ActiveSupport::Duration.build(125557).inspect
 => "1 day, 10 hours, 52 minutes, and 37 seconds"

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.