Wie konvertiert man einen Unix-Zeitstempel (Sekunden seit Epoche) in Ruby DateTime?
Antworten
Zu viele Anzeigen?Entschuldigung, kurzer Moment des Synapsenversagens. Hier ist die richtige Antwort.
require 'date'
Time.at(seconds_since_epoch_integer).to_datetime
Kurzes Beispiel (dabei wird die aktuelle Systemzeitzone berücksichtigt):
$ 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)>
Weitere Aktualisierung (für 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)>
Aktuelles Update : Ich habe die Top-Lösungen in diesem Thread verglichen, als ich vor ein oder zwei Wochen an einem HA-Dienst arbeitete, und war überrascht, dass Time.at(..)
besser abschneidet als DateTime.strptime(..)
(Update: weitere Benchmarks hinzugefügt).
# ~ % 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>
Handhabung von Zeitzonen
Ich möchte nur klarstellen, auch wenn dies bereits kommentiert wurde, damit künftige Personen diesen sehr wichtigen Unterschied nicht übersehen.
DateTime.strptime("1318996912",'%s') # => Wed, 19 Oct 2011 04:01:52 +0000
zeigt einen Rückgabewert in UTC an und erfordert, dass die Sekunden ein String sind und ein UTC-Zeitobjekt ausgegeben wird, während
Time.at(1318996912) # => 2011-10-19 00:01:52 -0400
zeigt einen Rückgabewert in der LOKALEN Zeitzone an, erfordert normalerweise ein FixNum-Argument, aber das Time-Objekt selbst ist immer noch in UTC, auch wenn die Anzeige nicht stimmt.
Obwohl ich also beiden Methoden dieselbe ganze Zahl übergeben habe, habe ich scheinbar zwei verschiedene Ergebnisse erhalten, weil die Methode der Klasse #to_s
Methode funktioniert. Wie @Eero mich jedoch zweimal daran erinnern musste:
Time.at(1318996912) == DateTime.strptime("1318996912",'%s') # => true
Ein Gleichheitsvergleich zwischen den beiden Rückgabewerten ergibt immer noch true. Dies liegt wiederum daran, dass die Werte grundsätzlich gleich sind (obwohl unterschiedliche Klassen, die #==
Methode übernimmt dies für Sie), aber die #to_s
Methode gibt drastisch unterschiedliche Zeichenketten aus. Wenn wir uns die Zeichenketten ansehen, können wir feststellen, dass es sich tatsächlich um dieselbe Zeit handelt, die nur in unterschiedlichen Zeitzonen gedruckt wird.
Klärung von Methodenargumenten
Die Dokumentation sagt auch: "Wenn ein numerisches Argument angegeben wird, ist das Ergebnis in lokaler Zeit", was Sinn macht, aber ein wenig verwirrend für mich war, weil es keine Beispiele für nicht-ganzzahlige Argumente in der Dokumentation gibt. Also, für einige nicht-ganzzahlige Argumente Beispiele:
Time.at("1318996912")
TypeError: can't convert String into an exact number
können Sie kein String-Argument verwenden, aber Sie können ein Time-Argument in Time.at
und gibt das Ergebnis in der Zeitzone des Arguments zurück:
Time.at(Time.new(2007,11,1,15,25,0, "+09:00"))
=> 2007-11-01 15:25:00 +0900
Benchmarks
Nach einer Diskussion mit @AdamEberlin über seine Antwort habe ich beschlossen, leicht veränderte Benchmarks zu veröffentlichen, um alles so gleich wie möglich zu machen. Außerdem möchte ich diese nie wieder bauen müssen, also ist dies ein guter Ort, um sie zu speichern.
Time.at(int).to_datetime ~ 2,8x schneller
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>
**** so bearbeitet, dass sie nicht in jeder Hinsicht völlig falsch ist****
****added benchmarks****
Ein Befehl zur Konvertierung von Datum und Uhrzeit in das Unix-Format und dann in einen String
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
schließlich wird strftime zum Formatieren des Datums verwendet
Beispiel:
irb(main):034:0> DateTime.strptime("1410321600",'%s').strftime("%d %m %y")
"10 09 14"
Hier wird die Anzahl der Sekunden in der Zukunft ab dem Zeitpunkt angegeben, an dem Sie den Code ausführen.
time = Time.new + 1000000000 #date in 1 billion seconds
puts(time)
Nach der aktuellen Uhrzeit, zu der ich die Frage beantworte, wird Folgendes ausgedruckt 047-05-14 05:16:16 +0000
(1 Milliarde Sekunden in der Zukunft)
oder wenn Sie eine Milliarde Sekunden von einem bestimmten Zeitpunkt an zählen wollen, dann im Format Time.mktime(year, month,date,hours,minutes)
time = Time.mktime(1987,8,18,6,45) + 1000000000
puts("Ich wäre 1 Milliarde Sekunden alt am: "+time)
- See previous answers
- Weitere Antworten anzeigen