Rails 3またはRubyで期間を時間:分:秒(または類似)に変換する


114

これを行う簡単な/組み込みの方法があるように感じますが、それを見つけることができません。

整数の期間(秒単位)があり、わかりやすい形式で表示したい。

たとえば、3600は「01:00:00」や「1時間」などと表示されます。

私はそれを行うことができますtime_ago_in_words(Time.zone.now+3600)が、それは少しハックのように感じます、この値をフォーマットするためだけに現在の時間から足したり引いたりする理由はありません。Aありますduration_in_words()か何かか?

ありがとう

回答:


82

参照:http : //api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html

distance_of_time_in_words(3600)
 => "about 1 hour"

1
おかげで私はそれを見ていたが、2回提供する必要があると思った。
シドニア2010年

1
ええ、これらの例は
ダフです

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

1
また、これを非常に具体的にし、期間を「丸め」たくない場合は、レーダーのgemを確認してください:github.com/radar/distance_of_time_in_words。のドロップイン交換で、オプションとしてdistance_of_time_in_words渡すことで丸められた数値を取得できvague: trueます。
Joshua Pinter

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"

使用オプション1を使用すると、単語をしたい場合は、オプション2を M:S形式、あなたはHしたい場合はオプション3を M:Sフォーマットと24時間以上があることができますが、Hをしたい場合


1
distance_of_time_in_wordsメソッドはActionViewヘルパーであるため、(コントローラーではなく)ビューから呼び出す必要があります。 api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html
msdundar

13
strftimeオプションは24時間でオーバーフローすることに注意してください。期間が25時間の場合は、と表示されます01:00:00
Gabe Martin-Dempesy

2
これは負の時間には機能しません。たとえば、-1800は-30mではなく-1h 30mを返します
Arnold Roa

43

Rubyの文字列%演算子はあまり評価されておらず、忘れられがちです。

"%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
それは「素敵な」の奇妙な定義です。
マークボリンジャー2015年

10
%「私の右からパラメータの配列を取ると私の左のフォーマット文字列に挿入してください。」と言います その点ではprintf、C \ C ++ と似ていますが、より簡潔であり、割り当てで使用できます。はい、私はそれを素敵と呼びます。そしてパワフル。この雄弁さをよりよく示す例がありますが、彼らは質問に答えません。ところで、あなたのヘビは高く評価されていません。
IAmNaN

26

あなたは次のようなこともできると思います:

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

必要に応じてフォーマットします。

ちなみに、もともとはTime.at()を使うことを考えていましたが、UbuntuのEPOCH時間は木曜日1月1日01:00:00 +0100 1970であり、期待した00:00:00時間ではないようです。

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

必要以上に1時間多くなります。


ああ、夏の時間のために何かすることはありますか?
クリストバルビエドマ2010年

7
唯一の問題は、24時間を超える時間を扱っている場合です。その場合、時間は低い数値にロールバックされます。
metavida 2011

24時間を超える場合、%jは日数を示します(365未満の場合)
BananaNeil

17

これを使用して、Railsプロジェクトの期間を表示します。

  1. Integerクラスにカスタムメソッドを追加します。あなたはと呼ばれる新しいファイルを作成することができますpretty_duration.rbinitializersフォルダを:

    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"
    

この答えは、Lev Lukomskyのコードに基づいています


よく働きました。これありがとう。
Donn Felker 2017年

13

これは、obscure 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

1日より長い期間に注意してください。

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

これがコーナーケースをどのように解決するかをハイライトする入出力の例を挙げてください
Cyril Duchon-Doris '16

4

Lev LukomskyのActiveSupport :: Durationを利用し、ミリ秒を処理する(ベンチマークコードに役立つ)から発想を得た回答

# 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か月の期間は日数で固定されないため、これは不正確になる可能性があることに注意してください。


2

ちょうど私の2セントを投入する:

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

Xiao Binの答えから構築されました。


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"

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.