¿Cómo se convierte entre un objeto DateTime y Time en Ruby?
¿Cómo se convierte entre un objeto DateTime y Time en Ruby?
Respuestas:
Necesitarás dos conversiones ligeramente diferentes.
Para convertir de Time
a DateTime
puede modificar la clase Time de la siguiente manera:
require 'date'
class Time
def to_datetime
# Convert seconds + microseconds into a fractional number of seconds
seconds = sec + Rational(usec, 10**6)
# Convert a UTC offset measured in minutes to one measured in a
# fraction of a day.
offset = Rational(utc_offset, 60 * 60 * 24)
DateTime.new(year, month, day, hour, min, seconds, offset)
end
end
Ajustes similares a Fecha le permitirán convertir DateTime
a Time
.
class Date
def to_gm_time
to_time(new_offset, :gm)
end
def to_local_time
to_time(new_offset(DateTime.now.offset-offset), :local)
end
private
def to_time(dest, method)
#Convert a fraction of a day to a number of microseconds
usec = (dest.sec_fraction * 60 * 60 * 24 * (10**6)).to_i
Time.send(method, dest.year, dest.month, dest.day, dest.hour, dest.min,
dest.sec, usec)
end
end
Tenga en cuenta que debe elegir entre la hora local y la hora GM / UTC.
Ambos fragmentos de código anteriores están tomados del libro de cocina Ruby de O'Reilly . Su política de reutilización de código lo permite.
require 'time'
require 'date'
t = Time.now
d = DateTime.now
dd = DateTime.parse(t.to_s)
tt = Time.parse(d.to_s)
Como una actualización del estado del ecosistema de Ruby Date
, DateTime
y Time
ahora tienen métodos para convertir entre las diferentes clases. Usando Ruby 1.9.2+:
pry
[1] pry(main)> ts = 'Jan 1, 2000 12:01:01'
=> "Jan 1, 2000 12:01:01"
[2] pry(main)> require 'time'
=> true
[3] pry(main)> require 'date'
=> true
[4] pry(main)> ds = Date.parse(ts)
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[5] pry(main)> ds.to_date
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[6] pry(main)> ds.to_datetime
=> #<DateTime: 2000-01-01T00:00:00+00:00 (4903089/2,0,2299161)>
[7] pry(main)> ds.to_time
=> 2000-01-01 00:00:00 -0700
[8] pry(main)> ds.to_time.class
=> Time
[9] pry(main)> ds.to_datetime.class
=> DateTime
[10] pry(main)> ts = Time.parse(ts)
=> 2000-01-01 12:01:01 -0700
[11] pry(main)> ts.class
=> Time
[12] pry(main)> ts.to_date
=> #<Date: 2000-01-01 (4903089/2,0,2299161)>
[13] pry(main)> ts.to_date.class
=> Date
[14] pry(main)> ts.to_datetime
=> #<DateTime: 2000-01-01T12:01:01-07:00 (211813513261/86400,-7/24,2299161)>
[15] pry(main)> ts.to_datetime.class
=> DateTime
1.9.3p327 :007 > ts = '2000-01-01 12:01:01 -0700' => "2000-01-01 12:01:01 -0700" 1.9.3p327 :009 > dt = ts.to_datetime => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :010 > dt.to_time => Sat, 01 Jan 2000 12:01:01 -0700 1.9.3p327 :011 > dt.to_time.class => DateTime
Desafortunadamente, las funciones DateTime.to_time, Time.to_datetime
y Time.parse
no retienen la información de la zona horaria. Todo se convierte a la zona horaria local durante la conversión. La aritmética de fechas todavía funciona, pero no podrá mostrar las fechas con sus zonas horarias originales. Esa información de contexto es a menudo importante. Por ejemplo, si quiero ver las transacciones realizadas durante el horario comercial en Nueva York, probablemente prefiera verlas en sus zonas horarias originales, no en mi zona horaria local en Australia (12 horas antes de Nueva York).
Los siguientes métodos de conversión mantienen esa información tz.
Para Ruby 1.8, mira la respuesta de Gordon Wilson . Es del viejo y confiable Ruby Cookbook.
Para Ruby 1.9, es un poco más fácil.
require 'date'
# Create a date in some foreign time zone (middle of the Atlantic)
d = DateTime.new(2010,01,01, 10,00,00, Rational(-2, 24))
puts d
# Convert DateTime to Time, keeping the original timezone
t = Time.new(d.year, d.month, d.day, d.hour, d.min, d.sec, d.zone)
puts t
# Convert Time to DateTime, keeping the original timezone
d = DateTime.new(t.year, t.month, t.day, t.hour, t.min, t.sec, Rational(t.gmt_offset / 3600, 24))
puts d
Esto imprime lo siguiente
2010-01-01T10:00:00-02:00
2010-01-01 10:00:00 -0200
2010-01-01T10:00:00-02:00
Se conserva toda la información original de DateTime, incluida la zona horaria.
Time#to_datetime
parece preservar tz para mí:Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Mejorando la solución de Gordon Wilson, aquí está mi intento:
def to_time
#Convert a fraction of a day to a number of microseconds
usec = (sec_fraction * 60 * 60 * 24 * (10**6)).to_i
t = Time.gm(year, month, day, hour, min, sec, usec)
t - offset.abs.div(SECONDS_IN_DAY)
end
Obtendrá la misma hora en UTC, perdiendo la zona horaria (desafortunadamente)
Además, si tienes ruby 1.9, prueba el to_time
método
Al realizar tales conversiones, uno debe tener en cuenta el comportamiento de las zonas horarias al convertir de un objeto a otro. Encontré algunas buenas notas y ejemplos en esta publicación de stackoverflow .