¿Cómo convertir una marca de tiempo de Unix (segundos desde la época) a Ruby DateTime?
¿Cómo se convierte una marca de tiempo de Unix (segundos desde la época) a Ruby DateTime?
Lo siento, breve momento de falla de sinapsis. Aquí está la verdadera respuesta.
require 'date'
Time.at(seconds_since_epoch_integer).to_datetime
Breve ejemplo (esto tiene en cuenta la zona horaria actual del sistema):
$ 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)>
Actualización adicional (para 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)>
Actualización reciente : comparé las mejores soluciones en este hilo mientras trabajaba en un servicio HA hace una o dos semanas y me sorprendió descubrir que Time.at(..)
superan las expectativas DateTime.strptime(..)
(actualización: se agregaron más puntos de referencia).
# ~ % 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>
DateTime.strptime
Puede manejar segundos desde la época. El número debe convertirse en una cadena:
require 'date'
DateTime.strptime("1318996912",'%s')
Manejo de zona horaria
Sólo quiero aclarar, aunque esto ya se ha comentado para que en el futuro no se pierda esta distinción tan importante.
DateTime.strptime("1318996912",'%s') # => Wed, 19 Oct 2011 04:01:52 +0000
muestra un valor de retorno en UTC y requiere que los segundos sean una cadena y genera un objeto de hora UTC, mientras que
Time.at(1318996912) # => 2011-10-19 00:01:52 -0400
muestra un valor de retorno en la zona horaria LOCAL, normalmente requiere un argumento FixNum, pero el objeto Time en sí todavía está en UTC aunque la visualización no lo esté.
Entonces, aunque pasé el mismo número entero a ambos métodos, aparentemente obtuve dos resultados diferentes debido a cómo #to_s
funciona el método de la clase. Sin embargo, como @Eero tuvo que recordarme dos veces:
Time.at(1318996912) == DateTime.strptime("1318996912",'%s') # => true
Una comparación de igualdad entre los dos valores devueltos aún devuelve verdadero. Nuevamente, esto se debe a que los valores son básicamente los mismos (aunque son clases diferentes, el #==
método se encarga de esto por usted), pero el #to_s
método imprime cadenas drásticamente diferentes. Aunque, si miramos las cadenas, podemos ver que efectivamente son la misma hora, solo que están impresas en diferentes zonas horarias.
Método Argumento Aclaración
Los documentos también dicen "Si se proporciona un argumento numérico, el resultado está en la hora local". lo cual tiene sentido, pero me resultó un poco confuso porque no dan ningún ejemplo de argumentos no enteros en los documentos. Entonces, para algunos ejemplos de argumentos no enteros:
Time.at("1318996912")
TypeError: can't convert String into an exact number
no puedes usar un argumento String, pero puedes usar un argumento Time into Time.at
y devolverá el resultado en la zona horaria del argumento:
Time.at(Time.new(2007,11,1,15,25,0, "+09:00"))
=> 2007-11-01 15:25:00 +0900
Puntos de referencia
Después de una discusión con @AdamEberlin sobre su respuesta, decidí publicar puntos de referencia ligeramente modificados para que todo sea lo más igualitario posible. Además, no quiero tener que volver a construirlos nunca más, así que este es un lugar tan bueno como cualquier otro para guardarlos.
Time.at(int).to_datetime ~ 2,8 veces más rápido
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>
****editado para no ser completa y totalmente incorrecto en todos los sentidos****
**** puntos de referencia agregados ****
Un comando para convertir fecha y hora al formato Unix y luego a cadena
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
finalmente se usa strftime para formatear la fecha
Ejemplo:
irb(main):034:0> DateTime.strptime("1410321600",'%s').strftime("%d %m %y")
"10 09 14"
Esto le indica la fecha de la cantidad de segundos en el futuro desde el momento en que ejecuta el código.
time = Time.new + 1000000000 #date in 1 billion seconds
pone (tiempo)
según la hora actual estoy respondiendo la pregunta que imprime 047-05-14 05:16:16 +0000
(mil millones de segundos en el futuro)
o si quieres contar mil millones de segundos a partir de un momento determinado, está en formatoTime.mktime(year, month,date,hours,minutes)
time = Time.mktime(1987,8,18,6,45) + 1000000000
puts("Tendría mil millones de segundos en: "+tiempo)