UNIXタイムスタンプ(エポックからの秒数)をRuby DateTimeに変換する方法は?


369

Unixタイムスタンプ(エポックからの秒数)をRuby DateTimeに変換するにはどうすればよいですか?

回答:


354

DateTime.strptimeエポック以降の秒を処理できます。数値は文字列に変換する必要があります:

require 'date'
DateTime.strptime("1318996912",'%s')

4
これは小数秒を処理しません
Dan Sandberg

45
これはミリ秒を処理します%Q
ミニジョン

3
@TheMiniJohnの回答をフォローアップする。のTime代わりにが必要なようですDateTime。したがって、使用するTime.strptime("1318996912345",'%Q').to_fと、ミリ秒が保持されていることがわかりますが、DateTime.strptime("1318996912345",'%Q').to_fは保持されません。
skensell 2017

625

申し訳ありませんが、シナプス障害が発生しました。これが本当の答えです。

require 'date'

Time.at(seconds_since_epoch_integer).to_datetime

簡単な例(これは現在のシステムのタイムゾーンを考慮に入れます):

$ date +%s
1318996912

$ irb

ruby-1.9.2-p180 :001 > require 'date'
 => true 

ruby-1.9.2-p180 :002 > Time.at(1318996912).to_datetime
 => #<DateTime: 2011-10-18T23:01:52-05:00 (13261609807/5400,-5/24,2299161)> 

さらに更新(UTCの場合):

ruby-1.9.2-p180 :003 > Time.at(1318996912).utc.to_datetime
 => #<DateTime: 2011-10-19T04:01:52+00:00 (13261609807/5400,0/1,2299161)>

最近の更新:1〜2週間前にHAサービスに取り組んでいるときに、このスレッドの上位ソリューションをベンチマークし、そのTime.at(..)パフォーマンスが優れていることに驚きましたDateTime.strptime(..)(更新:ベンチマークを追加しました)。

# ~ % ruby -v
#  => ruby 2.1.5p273 (2014-11-13 revision 48405) [x86_64-darwin13.0]

irb(main):038:0> Benchmark.measure do
irb(main):039:1*   ["1318996912", "1318496912"].each do |s|
irb(main):040:2*     DateTime.strptime(s, '%s')
irb(main):041:2>   end
irb(main):042:1> end

=> #<Benchmark ... @real=2.9e-05 ... @total=0.0>

irb(main):044:0> Benchmark.measure do
irb(main):045:1>   [1318996912, 1318496912].each do |i|
irb(main):046:2>     DateTime.strptime(i.to_s, '%s')
irb(main):047:2>   end
irb(main):048:1> end

=> #<Benchmark ... @real=2.0e-05 ... @total=0.0>

irb(main):050:0* Benchmark.measure do
irb(main):051:1*   ["1318996912", "1318496912"].each do |s|
irb(main):052:2*     Time.at(s.to_i).to_datetime
irb(main):053:2>   end
irb(main):054:1> end

=> #<Benchmark ... @real=1.5e-05 ... @total=0.0>

irb(main):056:0* Benchmark.measure do
irb(main):057:1*   [1318996912, 1318496912].each do |i|
irb(main):058:2*     Time.at(i).to_datetime
irb(main):059:2>   end
irb(main):060:1> end

=> #<Benchmark ... @real=2.0e-05 ... @total=0.0>

1
ありがとう...次の答えはもう少し簡潔です。Time.atを見つけましたが、同等のDateTimeを見つけようとしていました。
Tronathan '19年

27
おもしろいですが、可読性の理由だけでTime.at()。to_datetimeはDateTime.strptime()よりも快適に見えます...少なくとも私にとってはとにかく
tybro0103

34
これは上記のアンサーと同じではありません。Time.atはDateTime.strptimeがUTCを使用する現在のタイムゾーンを想定しています。
Vitaly Babiy 2013年

5
Time.atパフォーマンスが優れてDateTime.strptimeいることはそれほど驚くべきことではありません。後者は文字列を解析する必要がありますが、これは通常、数値を直接取り込むよりもはるかに低速です。
クロー

2
ベンチマークは厳密にテストしてDateTime.strptimeいるわけではありません。反復ごとに2つの新しい文字列を作成するため、非常にコストがかかります。@clawが言ったような文字列解析だけではありません
WattsInABox 2015年

67

タイムゾーンの取り扱い

これはコメントされていますが、将来の人々がこの非常に重要な区別を見逃さないようにしていますが、はっきりさせておきたいと思います。

DateTime.strptime("1318996912",'%s') # => Wed, 19 Oct 2011 04:01:52 +0000

戻り値をUTCで表示し、秒を文字列にする必要があり、UTC Timeオブジェクトを出力します。

Time.at(1318996912) # => 2011-10-19 00:01:52 -0400

はローカルタイムゾーンで戻り値を表示します。通常はFixNum引数が必要ですが、Timeオブジェクト自体は表示されていなくてもUTCのままです。

したがって、両方のメソッドに同じ整数を渡したとしても、クラスの#to_sメソッドがどのように機能するかにより、2つの異なる結果のように見えます。ただし、@ Eeroは私に2度思い出させる必要があったので、

Time.at(1318996912) == DateTime.strptime("1318996912",'%s') # => true

2つの戻り値の等価比較は依然としてtrueを返します。繰り返しますが、これは値が基本的に同じであるためです(クラスは異なりますが、#==メソッドがこれを処理します)が、#to_sメソッドは大幅に異なる文字列を出力します。文字列を見ると、実際には同じ時間帯で、異なるタイムゾーンで印刷されていることがわかります。

メソッド引数の明確化

ドキュメントはまた、「数値の引数が指定された場合、結果は現地時間になります」と述べています。これは理にかなっていますが、ドキュメントで整数以外の引数の例を示していないため、少し混乱しました。したがって、いくつかの非整数引数の例については、

Time.at("1318996912")
TypeError: can't convert String into an exact number

String引数は使用できませんが、Time引数を使用するTime.atと、引数のタイムゾーンで結果が返されます。

Time.at(Time.new(2007,11,1,15,25,0, "+09:00"))
=> 2007-11-01 15:25:00 +0900

ベンチマーク

@AdamEberlinと彼の答えについて話し合った後、すべてをできるだけ等しくするために、少し変更したベンチマークを公開することにしました。また、これらを再度ビルドする必要がないので、これを保存するのと同じくらい良い場所です。

Time.at(int).to_datetime〜2.8倍高速

09:10:58-watsw018:~$ ruby -v
ruby 2.3.7p456 (2018-03-28 revision 63024) [universal.x86_64-darwin18]
09:11:00-watsw018:~$ irb
irb(main):001:0> require 'benchmark'
=> true
irb(main):002:0> require 'date'
=> true
irb(main):003:0>
irb(main):004:0* format = '%s'
=> "%s"
irb(main):005:0> times = ['1318996912', '1318496913']
=> ["1318996912", "1318496913"]
irb(main):006:0> int_times = times.map(&:to_i)
=> [1318996912, 1318496913]
irb(main):007:0>
irb(main):008:0* datetime_from_strptime = DateTime.strptime(times.first, format)
=> #<DateTime: 2011-10-19T04:01:52+00:00 ((2455854j,14512s,0n),+0s,2299161j)>
irb(main):009:0> datetime_from_time = Time.at(int_times.first).to_datetime
=> #<DateTime: 2011-10-19T00:01:52-04:00 ((2455854j,14512s,0n),-14400s,2299161j)>
irb(main):010:0>
irb(main):011:0* datetime_from_strptime === datetime_from_time
=> true
irb(main):012:0>
irb(main):013:0* Benchmark.measure do
irb(main):014:1*   100_000.times {
irb(main):015:2*     times.each do |i|
irb(main):016:3*       DateTime.strptime(i, format)
irb(main):017:3>     end
irb(main):018:2>   }
irb(main):019:1> end
=> #<Benchmark::Tms:0x00007fbdc18f0d28 @label="", @real=0.8680500000045868, @cstime=0.0, @cutime=0.0, @stime=0.009999999999999998, @utime=0.86, @total=0.87>
irb(main):020:0>
irb(main):021:0* Benchmark.measure do
irb(main):022:1*   100_000.times {
irb(main):023:2*     int_times.each do |i|
irb(main):024:3*       Time.at(i).to_datetime
irb(main):025:3>     end
irb(main):026:2>   }
irb(main):027:1> end
=> #<Benchmark::Tms:0x00007fbdc3108be0 @label="", @real=0.33059399999910966, @cstime=0.0, @cutime=0.0, @stime=0.0, @utime=0.32000000000000006, @total=0.32000000000000006>

****すべての点で完全かつ完全に不正確にならないように編集されました****

****ベンチマークを追加****


3
もっともらしいと思われ、私はすでに賛成しました(今は取り消せません)が、さらに確認するとUTCに関するあなたの主張は正しくありません。結果のDateTime / TimeオブジェクトはUTCとローカルのどちらかになりますが、元のタイムスタンプはどちらの場合もUTCであると解釈されます。そのため、方法に関係なく、瞬間は等しくなります。Time.at(1318996912) == DateTime.strptime("1318996912",'%s')UTC以外のタイムゾーンで試してみてください。
Eero 2014

4
申し訳ありませんが、修正した内容はまだ間違っています!:-)実行Time.use_zone "Samoa" do Time.at(1318996912) == DateTime.strptime("1318996912",'%s') endして、時刻が等しいこと、ローカルタイムスタンプがないこと、およびどちらの場合でも、UnixタイムスタンプがUTCであると解釈されることを確認します。 Time.at プレゼントローカルタイムゾーンでの結果の時間オブジェクト、およびDateTime.strptime プレゼント UTCでの結果のDateTimeオブジェクトを、彼らは時間で同等の瞬間いるように関係なく、プレゼンテーションの彼らは、同じです。
Eero、2014年

ステートメントTime.at(1318996912) # => 2011-10-19 00:01:52 -0400LOCALタイムゾーンでの戻り値を表示するのに対し、 正確ではないようです...確認できますか?私はあなたの声明があなたが使用した場合にのみ真実であると信じていますTime.zone.at(1318996912)
BigRon

ええ、それは正確なようです。ローカルマシンはESTに設定されており、時刻はESTで表示されます。
WattsInABox 2017

これが@BigRonではない例を提供できますか?どのタイムゾーン、ルビバージョンなどがこのように動作しないのですか?
WattsInABox 2017

10

日付時刻をUnix形式に変換してから文字列に変換する1つのコマンド

    DateTime.strptime(Time.now.utc.to_i.to_s,'%s').strftime("%d %m %y")

    Time.now.utc.to_i #Converts time from Unix format
    DateTime.strptime(Time.now.utc.to_i.to_s,'%s') #Converts date and time from unix format to DateTime

最後にstrftimeを使用して日付をフォーマットします

例:

    irb(main):034:0> DateTime.strptime("1410321600",'%s').strftime("%d %m %y")
    "10 09 14"

注意すべき点の1つは、エポック形式にはタイムゾーンがないため、to_iをチェーンする前にutcをチェーンする必要がないことですTime.now.utc.to_i
Trevor McCasland

1

これにより、コードを実行した時点からの未来の秒数の日付がわかります。

time = Time.new + 1000000000 #date in 1 billion seconds

puts(time)

表示されている質問に答えている現在の時間047-05-14 05:16:16 +0000(将来10億秒)に応じて

または、特定の時間から10億秒をカウントする場合は、それは形式です Time.mktime(year, month,date,hours,minutes)

time = Time.mktime(1987,8,18,6,45) + 1000000000

puts( "私は10億秒前になるでしょう:" + time)


0

日付だけが必要なDate.strptime(invoice.date.to_s, '%s')場合invoice.dateは、の形式でを実行してFixnumからに変換できますString


3
Time.at(1500923406).to_date.to_s=>"2017-07-24"
クロエ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.