Unix zaman damgasını (çağdan bu yana saniye) Ruby DateTime'e nasıl dönüştürebilirim?


369

Unix zaman damgasını (dönemden bu yana saniye) Ruby DateTime'a nasıl dönüştürebilirsiniz?

Yanıtlar:


354

DateTime.strptimedönemden bu yana saniyeler işleyebilir. Sayı bir dizeye dönüştürülmelidir:

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

4
Bu kesirli saniyelerle başa çıkmıyor
Dan Sandberg

45
%QTho ile milisaniye işliyor.
Mini John

3
@ TheMiniJohn'un cevabını takip etmek için. Bunun Timeyerine gerekli gibi görünüyor DateTime. Bu yüzden kullanın Time.strptime("1318996912345",'%Q').to_fve koruyamazken, milisaniyenin korunduğunu göreceksiniz DateTime.strptime("1318996912345",'%Q').to_f.
skensell

625

Üzgünüz, kısa bir sinaps anı. İşte gerçek cevap.

require 'date'

Time.at(seconds_since_epoch_integer).to_datetime

Kısa örnek (bu, geçerli sistem saat dilimini dikkate alır):

$ 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)> 

Daha fazla güncelleme (UTC için):

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)>

Son Güncelleme : Bir ya da iki hafta önce bir HA hizmetinde çalışırken bu iş parçacığındaki en iyi çözümleri karşılaştırdım ve Time.at(..)daha iyi performanslar bulduğuna şaşırdım DateTime.strptime(..)(güncelleme: daha fazla kıyaslama eklendi).

# ~ % 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
Teşekkür ederim ... Aşağıdaki cevap biraz daha özlü, Time.at'ı buldum ama bir DateTime eşdeğeri bulmaya çalışıyordum.
Tronathan

27
Komik ama Time.at (). To_datetime, sadece okunabilirlik nedeniyle DateTime.strptime () 'den daha hoş görünüyor ... En azından benim için her durumda
tybro0103

34
Bu, yukarıdaki anser ile aynı değildir, Time.at, DateTime.strptime öğesinin UTC kullandığı geçerli saat dilimini varsayar.
Vitaly Babiy

5
Daha Time.atiyi performans göstermesi çok şaşırtıcı değil DateTime.strptime. İkincisi, bir sayıyı doğrudan almaktan genellikle daha yavaş olan bir dizeyi ayrıştırmak zorundadır.
Pençe

2
Karşılaştırmanız tam olarak test değildir, DateTime.strptimeçünkü her yinelemede çok pahalı olan iki yeni Dizge oluşturur. @Claw'un dediği gibi sadece dize ayrıştırma değil
WattsInABox

67

Zaman Dilimi İşleme

Açıklamak istiyorum, bu yorumlanmış olsa da, gelecekteki insanlar bu çok önemli ayrımı kaçırmazlar.

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

UTC'de bir dönüş değeri görüntüler ve saniyeler bir String olmasını gerektirir ve bir UTC Time nesnesi çıkarır

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

LOCAL saat diliminde bir dönüş değeri görüntüler, normalde bir FixNum bağımsız değişkeni gerektirir, ancak ekran olmasa da Time nesnesinin kendisi hala UTC konumundadır.

Her iki yönteme de aynı tamsayıyı geçirmiş olmama rağmen, sınıf #to_syönteminin nasıl çalıştığı nedeniyle görünüşte iki farklı sonuç aldım . Ancak, @ Eero bana iki kez hatırlatmak zorunda kaldı:

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

İki dönüş değeri arasındaki eşitlik karşılaştırması yine de true değerini döndürür. Yine, bunun nedeni değerlerin temelde aynı olmasıdır (farklı sınıflar olmasına rağmen, #==yöntem sizin için bunu halleder), ancak #to_syöntem büyük ölçüde farklı dizeler yazdırır. Her ne kadar, dizelere bakarsak, aslında aynı zamanda, sadece farklı saat dilimlerinde basıldığını görebiliriz.

Yöntem Bağımsız Değişken Açıklama

Dokümanlar ayrıca "Sayısal bir bağımsız değişken verilirse sonuç yerel saattedir" der. bu mantıklı, ama benim için biraz kafa karıştırıcıydı çünkü dokümanlardaki tamsayı olmayan argümanlara örnek vermiyorlar. Yani, bazı tamsayı olmayan argüman örnekleri için:

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

bir String bağımsız değişkeni kullanamazsınız, ancak içine bir Time bağımsız değişkeni kullanabilirsiniz; Time.atbu, sonucu bağımsız değişkenin saat diliminde döndürür:

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

Deneyler

@AdamEberlin ile yaptığı cevap üzerine bir tartışmadan sonra, her şeyi olabildiğince eşit hale getirmek için biraz değiştirilmiş kriterler yayınlamaya karar verdim. Ayrıca, bunları tekrar inşa etmek istemiyorum, bu yüzden onları kurtarmak için herhangi bir yer.

Time.at (int) .to_datetime ~ 2.8x daha hızlı

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>

**** her şekilde tamamen ve tamamen yanlış olmayacak şekilde düzenlendi ****

**** kriterler eklendi ****


3
Mantıklı görünüyordu ve zaten iptal ettim (şimdi iptal edemiyorum), ancak UTC ile ilgili iddianızı daha fazla kontrol ettikten sonra doğru değil. Ortaya çıkan DateTime / Time nesnesi UTC'ye karşı yerel olacak, evet, ancak orijinal zaman damgası her iki durumda da UTC'de olarak yorumlanıyor! Dolayısıyla, zaman ne olursa olsun, yöntem ne olursa olsun eşittir. Time.at(1318996912) == DateTime.strptime("1318996912",'%s')UTC dışı bir saat diliminde deneyin ve göreceksiniz!
Eero

4
Üzgünüm, ama düzelttiğiniz şey hala yanlış! :-) Time.use_zone "Samoa" do Time.at(1318996912) == DateTime.strptime("1318996912",'%s') endZamanların eşit olduğunu doğrulamak için çalıştır , LOCAL zaman damgası yok ve her iki durumda da Unix zaman damgası UTC olarak yorumlanıyor. Time.at hediyeler yerel saat diliminde sonuçlanan Zaman nesne ve DateTime.strptime hediyeler bunlar zamanla eşdeğer an olduğu gibi UTC sonuçlanan DateTime nesnesi, ama ne olursa olsun sunumun onlar, eşittir.
Eero

İfadesi ise Time.at(1318996912) # => 2011-10-19 00:01:52 -0400YEREL saat diliminde bir dönüş değeri görüntüler doğru görünmüyor ... doğrulayıp misiniz? Time.zone.at(1318996912)
İfadenizin

Evet, bu doğru gibi görünüyor. Yerel makinem EST olarak ayarlanmış ve saatler EST'de görüntüleniyor.
WattsInABox

@BigRon durumunun böyle olmadığı bir örnek verebilir misiniz? Hangi saat dilimi, yakut versiyonu vb. Bu şekilde davranmaz?
WattsInABox

10

Tarih saatini Unix biçimine ve sonra dizeye dönüştürmek için bir komut

    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

son olarak strftime tarihi formatlamak için kullanılır

Misal:

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

Dikkat edilmesi gereken bir nokta, epoch formatının bir saat dilimine sahip olmamasıdır, bu nedenle to_i'yi zincirlemeden önce utc'nin zincirlenmesi gerekli değildir Time.now.utc.to_i.
Trevor McCasland

1

Bu, kodu yürüttüğünüz andan itibaren gelecekteki saniye sayısını bildirir.

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

koyar (zaman)

şimdiki zamana göre bastığım soruyu cevaplıyorum 047-05-14 05:16:16 +0000(gelecekte 1 milyar saniye)

veya belirli bir zamandan milyar saniye saymak istiyorsanız, Time.mktime(year, month,date,hours,minutes)

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

("Şu tarihte 1 Milyar saniye olurdu:" + süre)


0

Sadece bir Tarih istiyorsanız, Date.strptime(invoice.date.to_s, '%s')nerede invoice.dateve şeklinde Fixnumdönüştürülür bir yerde yapabilirsiniz String.


3
Time.at(1500923406).to_date.to_s=>"2017-07-24"
Chloe
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.