No estoy seguro de si esta debería ser una pregunta separada, pero ¿cómo se convierte entre una fecha y una hora?
Andrew Grimm
8
Las respuestas aceptadas y mejor calificadas ya no son las más precisas en las versiones modernas de Ruby. Vea las respuestas de @theTinMan y @PatrickMcKenzie a continuación.
Phrogz
Respuestas:
50
Necesitarás dos conversiones ligeramente diferentes.
Para convertir de Time a DateTimepuede modificar la clase Time de la siguiente manera:
require 'date'classTimedef 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)endend
Ajustes similares a Fecha le permitirán convertir DateTime a Time .
classDatedef to_gm_time
to_time(new_offset,:gm)enddef to_local_time
to_time(new_offset(DateTime.now.offset-offset),:local)end
privatedef 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_iTime.send(method, dest.year, dest.month, dest.day, dest.hour, dest.min,
dest.sec, usec)endend
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.
Esto se interrumpirá en 1.9 donde DateTime # sec_fraction devuelve el número de milisegundos en un segundo. Para 1.9 que desea utilizar: usec = dest.sec_fraction * 10 ** 6
dkubb
185
require 'time'
require 'date'
t =Time.now
d =DateTime.now
dd =DateTime.parse(t.to_s)
tt =Time.parse(d.to_s)
+1 Puede que no sea la ejecución más eficiente, pero funciona, es conciso y es muy legible.
Walt Jones
66
Desafortunadamente, esto solo funciona cuando se trata de horarios locales. Si comienza con un DateTime u Time con una zona horaria diferente, la función de análisis se convertirá en zona horaria local. Básicamente pierdes la zona horaria original.
Bernard
66
A partir de ruby 1.9.1, DateTime.parse conserva la zona horaria. (No tengo acceso a versiones anteriores). Time.parse no conserva la zona horaria, porque representa el tiempo_t estándar POSIX, que creo que es una diferencia entera de la época. Cualquier conversión al tiempo debe tener el mismo comportamiento.
anshul
1
Tienes razón. DateTime.parse funciona en 1.9.1 pero no Time.parse. En cualquier caso, es menos propenso a errores (consistente) y probablemente más rápido usar DateTime.new (...) y Time.new (..). Vea mi respuesta para el código de muestra.
Bernard
1
Hola @anshul No estoy implicando que estoy diciendo :-). La información de zona horaria no se mantiene cuando se usa Time.parse (). Es fácil de probar. En su código anterior, simplemente reemplace d = DateTime.now con d = DateTime.new (2010,01,01, 10,00,00, Rational (-2, 24)). Ahora mostrará la fecha d convertida a su zona horaria local. Todavía puede hacer aritmética de fechas y todo, pero se pierde la información original de tz. Esta información es un contexto para la fecha y a menudo es importante. Ver aquí: stackoverflow.com/questions/279769/...
Bernard
63
Como una actualización del estado del ecosistema de Ruby Date, DateTimey Timeahora tienen métodos para convertir entre las diferentes clases. Usando Ruby 1.9.2+:
Ups Me acabo de dar cuenta de que este es un problema de Ruby on Rails, no un problema de Ruby: stackoverflow.com/questions/11277454/… . Incluso tenían un error archivado contra este método en la línea 2.x y lo marcaron "no solucionará". Decisión horrible en mi humilde opinión. El comportamiento de Rails rompe totalmente la interfaz subyacente de Ruby.
Jesse Clark
12
Desafortunadamente, las funciones DateTime.to_time, Time.to_datetimey Time.parseno 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.
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
El tiempo es complicado, pero no hay excusa para no proporcionar una conversión integrada entre diferentes clases de tiempo incorporado. Puede lanzar una RangeException si intenta obtener un UNIX time_t para 4713 BC (aunque un valor negativo BigNum sería mejor), pero al menos proporcionar un método para ello.
Mark Reed
1
Time#to_datetimeparece preservar tz para mí:Time.local(0).to_datetime.zone #=> "-07:00"; Time.gm(0).to_datetime.zone #=> "+00:00"
Phrogz
El desplazamiento de @Phrogz UTC no es lo mismo que una zona horaria. Uno es constante, el otro puede cambiar en diferentes momentos del año para el horario de verano. DateTime no tiene una zona, ignora el horario de verano. El tiempo lo respeta, pero solo en el TZ "local" (entorno del sistema).
Andrew Vit
1
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_timemé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 .
Respuestas:
Necesitarás dos conversiones ligeramente diferentes.
Para convertir de
Time
aDateTime
puede modificar la clase Time de la siguiente manera:Ajustes similares a Fecha le permitirán convertir
DateTime
aTime
.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.
fuente
fuente
Como una actualización del estado del ecosistema de Ruby
Date
,DateTime
yTime
ahora tienen métodos para convertir entre las diferentes clases. Usando Ruby 1.9.2+:fuente
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
yTime.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.
Esto imprime lo siguiente
Se conserva toda la información original de DateTime, incluida la zona horaria.
fuente
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:
Obtendrá la misma hora en UTC, perdiendo la zona horaria (desafortunadamente)
Además, si tienes ruby 1.9, prueba el
to_time
métodofuente
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 .
fuente