¿Cómo convertir una marca de tiempo de Unix (segundos desde la época) a Ruby DateTime?

Resuelto Tronathan asked hace 12 años • 6 respuestas

¿Cómo se convierte una marca de tiempo de Unix (segundos desde la época) a Ruby DateTime?

Tronathan avatar Oct 19 '11 10:10 Tronathan
Aceptado

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>
Adam Eberlin avatar Oct 19 '2011 03:10 Adam Eberlin

DateTime.strptimePuede manejar segundos desde la época. El número debe convertirse en una cadena:

require 'date'
DateTime.strptime("1318996912",'%s')
steenslag avatar Oct 19 '2011 09:10 steenslag

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_sfunciona 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_smé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.aty 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 ****

WattsInABox avatar Oct 17 '2013 15:10 WattsInABox

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"
Tejasvi Manmatha avatar Feb 12 '2014 15:02 Tejasvi Manmatha

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)

sbutterworth avatar Sep 05 '2015 03:09 sbutterworth