Los documentos tienen una sección que explica cuándo usar qué.
x-yuri
Respuestas:
177
Las versiones más recientes de Ruby (2.0+) realmente no tienen diferencias significativas entre las dos clases. Algunas bibliotecas usarán una u otra por razones históricas, pero el nuevo código no necesariamente debe preocuparse. Elegir uno por coherencia es probablemente el mejor, así que intente combinar con lo que esperan sus bibliotecas. Por ejemplo, ActiveRecord prefiere DateTime.
En versiones anteriores a Ruby 1.9 y en muchos sistemas, el tiempo se representa como un valor con signo de 32 bits que describe el número de segundos desde el 1 de enero de 1970 UTC, una envoltura delgada alrededor de un time_tvalor estándar POSIX , y está limitado:
Time.at(0x7FFFFFFF)# => Mon Jan 18 22:14:07 -0500 2038Time.at(-0x7FFFFFFF)# => Fri Dec 13 15:45:53 -0500 1901
Las versiones más nuevas de Ruby pueden manejar valores más grandes sin producir errores.
DateTime es un enfoque basado en el calendario donde el año, mes, día, hora, minuto y segundo se almacenan individualmente. Esta es una construcción de Ruby on Rails que sirve como envoltorio alrededor de los campos DATETIME estándar de SQL. Estos contienen fechas arbitrarias y pueden representar casi cualquier punto en el tiempo ya que el rango de expresión es típicamente muy grande.
DateTime.new
# => Mon, 01 Jan -4712 00:00:00 +0000
Por lo tanto, es tranquilizador que DateTime pueda manejar publicaciones de blog de Aristóteles.
Al elegir uno, las diferencias son algo subjetivas ahora. Históricamente, DateTime ha proporcionado mejores opciones para manipularlo en forma de calendario, pero muchos de estos métodos también se han transferido a Time, al menos dentro del entorno Rails.
Si está trabajando con fechas, diría que use DateTime. El tiempo es conveniente para representar cosas como la hora actual del día o puntos en el futuro cercano, como 10.minutes.from_now. Los dos tienen mucho en común, aunque, como se señaló, DateTime puede representar un rango mucho más amplio de valores.
tadman
3
Creo que es porque Ruby cambia a Bignum de longitud arbitraria de Fixnum de 32 bits cuando experimenta un desbordamiento. Los números fuera de ese rango pueden no ser compatibles con aplicaciones externas. Sí, en 2038 estamos básicamente jodidos hasta que todos podamos acordar un formato de tiempo de 64 bits adecuado. El jurado aún está fuera.
tadman
28
Esta respuesta es anterior a 1.9.2. Ignore todo lo que dice sobre las limitaciones posix de Time, y haga su elección en función de las API de Time y DateTime.
Ben Nagy
8
Esta respuesta está desactualizada ¿verdad? Ahora se recomienda utilizar ActiveSupport de Time or Rail :: WithTimeZone. Ya no necesitas usar DateTime. Está ahí para la compatibilidad con versiones anteriores.
DateTime no considera ningún segundo bisiesto, no rastrea ninguna regla de horario de verano.
Lo que no se ha observado en este hilo antes es una de las pocas ventajas de DateTime: es consciente de las reformas de calendario, mientras Timeque no es:
[...] La clase Ruby's Time implementa un calendario gregoriano proleptico y no tiene un concepto de reforma de calendario [...].
La documentación de referencia concluye con la recomendación de usar Timecuando se trata exclusivamente de fechas / horas pasadas, actuales o futuras y solo DateTimecuando, por ejemplo, el cumpleaños de Shakespeare debe convertirse con precisión: (énfasis agregado)
Entonces, ¿cuándo debe usar DateTime en Ruby y cuándo debe usar Time? Es casi seguro que querrá usar Time ya que su aplicación probablemente esté tratando con fechas y horas actuales. Sin embargo, si necesita lidiar con fechas y horas en un contexto histórico, querrá usar DateTime [...]. Si también tiene que lidiar con zonas horarias, la mejor de las suertes: tenga en cuenta que probablemente estará lidiando con los horarios solares locales, ya que no fue hasta el siglo XIX que la introducción de los ferrocarriles exigió la necesidad de un horario estándar. y eventualmente zonas horarias.
[/ Editar julio 2018]
A partir de ruby 2.0, la mayoría de la información en las otras respuestas está desactualizada.
En particular, Timeahora está prácticamente sin consolidar. Puede estar a más o menos de 63 bits de distancia de Epoch:
irb(main):001:0> RUBY_VERSION
=>"2.0.0"
irb(main):002:0>Time.at(2**62-1).utc # within Integer range=>146138514283-06-1907:44:38 UTC
irb(main):003:0>Time.at(2**128).utc # outside of Integer range=>10783118943836478994022445751222-08-0608:03:51 UTC
irb(main):004:0>Time.at(-2**128).utc # outside of Integer range=>-10783118943836478994022445747283-05-2815:55:44 UTC
La única consecuencia del uso de valores más grandes debería ser el rendimiento, que es mejor cuando Integerse usan Bignums ( frente a s (valores fuera del Integerrango) o Rationals (cuando se rastrean nanosegundos)):
Desde Ruby 1.9.2, la implementación de Time utiliza un entero de 63 bits con signo, Bignum o Rational. El número entero es un número de nanosegundos desde la época que puede representar 1823-11-12 a 2116-02-20. Cuando se usa Bignum o Rational (antes de 1823, después de 2116, en nanosegundos), el tiempo funciona más lento como cuando se usa un entero. ( http://www.ruby-doc.org/core-2.1.0/Time.html )
En otras palabras, hasta donde yo entiendo, DateTimeya no cubre un rango más amplio de valores potenciales queTime .
Además, DateTimeprobablemente deberían tenerse en cuenta dos restricciones no mencionadas anteriormente :
Para que funcione el ejemplo anterior Time, el sistema operativo debe admitir segundos bisiestos y la información de la zona horaria debe configurarse correctamente, por ejemplo, a través deTZ=right/UTC irb (en muchos sistemas Unix).
En segundo lugar, DateTimetiene una comprensión muy limitada de las zonas horarias y, en particular, no tiene un concepto de horario de verano . Prácticamente maneja zonas horarias como simples compensaciones UTC + X:
Esto puede causar problemas cuando las horas se ingresan como DST y luego se convierten en una zona horaria que no es DST sin realizar un seguimiento de las compensaciones correctas fuera de DateTime sí mismo (muchos sistemas operativos ya pueden ocuparse de esto por usted).
En general, diría que hoy en día Timees la mejor opción para la mayoría de las aplicaciones.
También tenga en cuenta una diferencia importante en la suma: cuando agrega un número a un objeto Time, se cuenta en segundos, pero cuando agrega un número a DateTime, se cuenta en días.
Todavía es cierto en Ruby 2.5.1. ruby-doc.org/stdlib-2.5.1/libdoc/date/rdoc/DateTime.html : "DateTime no considera ningún segundo bisiesto, no rastrea ninguna regla de horario de verano". Sin embargo, tenga en cuenta que DateTime tiene ventajas cuando necesita lidiar con fechas / horas de calendario pre-gregorianas. Esto no se mencionó aquí antes, pero está documentado en la documentación de referencia: "[...] La clase Ruby's Time implementa un calendario gregoriano proleptico y no tiene un concepto de reforma de calendario [...]". Editaré mi respuesta para proporcionar más detalles.
Niels Ganser
Timetampoco tiene un concepto de segundos intercalares, por lo que no es diferente de DateTime. No sé dónde ejecutó sus ejemplos, pero lo intenté Time.new(2012,6,30,23,59,60,0)en diferentes versiones de Ruby, de 2.0 a 2.7, y siempre lo obtuve 2012-07-01 00:00:00 +0000.
michau
@michau Si Timeadmite segundos intercalares o no, depende de la configuración de su sistema operativo y zona horaria. Por ejemplo: TZ=right/UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'=> 2012-06-30 23:59:60 +0000mientras que TZ=UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'=> 2012-07-01 00:00:00 +0000.
Niels Ganser
@NielsGanser Genial, gracias! Sugerí una edición para aclarar este punto.
michau
44
Creo que la respuesta a "cuál es la diferencia" es una de las desafortunadas respuestas comunes a esta pregunta en las bibliotecas estándar de Ruby: las dos clases / libs fueron creadas de manera diferente por diferentes personas en diferentes momentos. Es una de las desafortunadas consecuencias de la naturaleza comunitaria de la evolución de Ruby en comparación con el desarrollo cuidadosamente planificado de algo como Java. Los desarrolladores quieren una nueva funcionalidad pero no quieren pisar las API existentes, por lo que solo crean una nueva clase; para el usuario final no hay una razón obvia para que existan las dos.
Esto es cierto para las bibliotecas de software en general: a menudo la razón por la que algún código o API es la forma en que resulta ser histórica en lugar de lógica.
La tentación es comenzar con DateTime porque parece más genérico. Fecha ... y hora, ¿verdad? Incorrecto. El tiempo también mejora las fechas, y de hecho puede analizar zonas horarias donde DateTime no puede. También se desempeña mejor.
Terminé usando el tiempo en todas partes.
Sin embargo, para estar seguro, tiendo a permitir que los argumentos de DateTime se pasen a mis API Timey, y convertirlos. Además, si sé que ambos tienen el método que me interesa, acepto cualquiera de ellos, como este método que escribí para convertir tiempos a XML (para archivos XMLTV)
# Will take a date time as a string or as a Time or DateTime object and# format it appropriately for xmtlv. # For example, the 22nd of August, 2006 at 20 past midnight in the British Summertime# timezone (i.e. GMT plus one hour for DST) gives: "20060822002000 +0100"defself.format_date_time(date_time)if(date_time.respond_to?(:rfc822))thenreturn format_time(date_time)else
time =Time.parse(date_time.to_s)return format_time(time)endend# Note must use a Time, not a String, nor a DateTime, nor Date.# see format_date_time for the more general versiondefself.format_time(time)# The timezone feature of DateTime doesn't work with parsed times for some reason# and the timezone of Time is verbose like "GMT Daylight Saving Time", so the only# way I've discovered of getting the timezone in the form "+0100" is to use # Time.rfc822 and look at the last five charsreturn"#{time.strftime( '%Y%m%d%H%M%S' )} #{time.rfc822[-5..-1]}"end
Además, Time.new y DateTime.new tratan la zona horaria de manera diferente. Estoy en GMT + 7, así que Time.new(2011, 11, 1, 10, 30)produce 2011-11-01 10:30:00 +0700mientras DateTime.new(2011, 11, 1, 10, 30)produce Tue, 01 Nov 2011 10:30:00 +0000.
Phương Nguyễn
21
Y como todos sabemos, el desarrollo cuidadosamente planificado de Java resultó en API lógicas y exclusivamente simples.
pje
@ PhươngNguyễn: ¿Podrían agregar eso como respuesta para que pueda votar? Esa es precisamente la razón por la que decidí elegir Time en DateTime.
Senseful
@Senseful Lo siento, no he recibido tu mensaje hasta ahora. La gente ya da algunos votos a mi comentario, así que creo que es genial aquí.
Phương Nguyễn
@ PhươngNguyễn Hola, ¿alguna idea de cómo / por qué esta diferencia en las zonas horarias? ¿De dónde está tomando el desplazamiento?
Joel_Blum
10
Descubrí que cosas tales como analizar y calcular el inicio / final de un día en diferentes zonas horarias son más fáciles de hacer con DateTime, suponiendo que esté utilizando las extensiones ActiveSupport .
En mi caso, necesitaba calcular el final del día en la zona horaria de un usuario (arbitraria) en función de la hora local del usuario que recibí como una cadena, por ejemplo, "2012-10-10 10:10 +0300"
Con DateTime es tan simple como
irb(main):034:0>DateTime.parse('2012-10-10 10:10 +0300').end_of_day
=>Wed,10Oct201223:59:59+0300# it preserved the timezone +0300
Ahora intentemos de la misma manera con Time:
irb(main):035:0>Time.parse('2012-10-10 10:10 +0300').end_of_day
=>2012-10-1023:59:59+0000# the timezone got changed to the server's default UTC (+0000), # which is not what we want to see here.
En realidad, Time necesita saber la zona horaria antes de analizar (también tenga en cuenta que Time.zone.parseno Time.parse):
irb(main):044:0>Time.zone ='EET'=>"EET"
irb(main):045:0>Time.zone.parse('2012-10-10 10:10 +0300').end_of_day
=>Wed,10Oct201223:59:59 EEST +03:00
Entonces, en este caso, definitivamente es más fácil usar DateTime.
Usando esto en la producción ahora, ¿hay algún inconveniente en la técnica?
Alex Moore-Niemi
1
DateTime no tiene en cuenta el horario de verano. Por lo tanto, al ahorrar tiempo de cambio, no funcionará correctamente. DateTime.parse('2014-03-30 01:00:00 +0100').end_of_dayproduce Sun, 30 Mar 2014 23:59:59 +0100, pero Time.zone = 'CET'; Time.zone.parse('2014-03-30 01:00:00').end_of_dayproduce Sun, 30 Mar 2014 23:59:59 CEST +02:00(CET = + 01: 00, CEST = + 02: 00 - observe que el desplazamiento ha cambiado). Pero para hacer esto, necesita más información sobre la zona horaria del usuario (no solo la compensación sino también si se usa el ahorro de tiempo).
Petr '' Bubák '' Šedivý
1
Puede indicar lo obvio, pero Time.zone.parsees muy útil al analizar los tiempos con diferentes zonas: te obliga a pensar qué zona deberías usar. A veces, Time.find_zone funciona aún mejor.
prusswan
1
@ Petr''Bubák''Šedivý analizó DateTimeel desplazamiento que le diste, que fue +0100. No proporcionó Timeun desplazamiento, pero una zona horaria ("CET" no describe un desplazamiento, es el nombre de una zona horaria). Las zonas horarias pueden tener diferentes compensaciones durante todo el año, pero una compensación es una compensación y siempre es la misma.
Mecki
4
Considere cómo manejan las zonas horarias de manera diferente con instancias personalizadas:
Esa es una observación interesante, pero debería explicarse por qué sucede. Date(como era de esperar) analiza solo las fechas, y cuando Datese convierte a Time, siempre usa la medianoche en la zona horaria local como la hora. La diferencia entre Timey se TimeDatederiva del hecho de que Timeno comprende BST, lo cual es sorprendente, dado que las zonas horarias generalmente se manejan más correctamente Time(con respecto al horario de verano, por ejemplo). Entonces, en este caso, solo DateTimeanaliza la cadena completa correctamente.
Tenga en cuenta que la Guía de estilo Ruby establece claramente una posición al respecto:
Sin fecha y hora
No use DateTime a menos que necesite tener en cuenta la reforma del calendario histórico, y si lo hace, especifique explícitamente el argumento de inicio para establecer claramente sus intenciones.
# bad - uses DateTime for current timeDateTime.now
# good - uses Time for current timeTime.now
# bad - uses DateTime for modern dateDateTime.iso8601('2016-06-29')# good - uses Date for modern dateDate.iso8601('2016-06-29')# good - uses DateTime with start argument for historical dateDateTime.iso8601('1751-04-23',Date::ENGLAND)
Respuestas:
Las versiones más recientes de Ruby (2.0+) realmente no tienen diferencias significativas entre las dos clases. Algunas bibliotecas usarán una u otra por razones históricas, pero el nuevo código no necesariamente debe preocuparse. Elegir uno por coherencia es probablemente el mejor, así que intente combinar con lo que esperan sus bibliotecas. Por ejemplo, ActiveRecord prefiere DateTime.
En versiones anteriores a Ruby 1.9 y en muchos sistemas, el tiempo se representa como un valor con signo de 32 bits que describe el número de segundos desde el 1 de enero de 1970 UTC, una envoltura delgada alrededor de un
time_t
valor estándar POSIX , y está limitado:Las versiones más nuevas de Ruby pueden manejar valores más grandes sin producir errores.
DateTime es un enfoque basado en el calendario donde el año, mes, día, hora, minuto y segundo se almacenan individualmente. Esta es una construcción de Ruby on Rails que sirve como envoltorio alrededor de los campos DATETIME estándar de SQL. Estos contienen fechas arbitrarias y pueden representar casi cualquier punto en el tiempo ya que el rango de expresión es típicamente muy grande.
Por lo tanto, es tranquilizador que DateTime pueda manejar publicaciones de blog de Aristóteles.
Al elegir uno, las diferencias son algo subjetivas ahora. Históricamente, DateTime ha proporcionado mejores opciones para manipularlo en forma de calendario, pero muchos de estos métodos también se han transferido a Time, al menos dentro del entorno Rails.
fuente
[Editar julio de 2018]
Todo lo siguiente sigue siendo válido en Ruby 2.5.1. De la documentación de referencia :
Lo que no se ha observado en este hilo antes es una de las pocas ventajas de
DateTime
: es consciente de las reformas de calendario, mientrasTime
que no es:La documentación de referencia concluye con la recomendación de usar
Time
cuando se trata exclusivamente de fechas / horas pasadas, actuales o futuras y soloDateTime
cuando, por ejemplo, el cumpleaños de Shakespeare debe convertirse con precisión: (énfasis agregado)[/ Editar julio 2018]
A partir de ruby 2.0, la mayoría de la información en las otras respuestas está desactualizada.
En particular,
Time
ahora está prácticamente sin consolidar. Puede estar a más o menos de 63 bits de distancia de Epoch:La única consecuencia del uso de valores más grandes debería ser el rendimiento, que es mejor cuando
Integer
se usanBignum
s ( frente a s (valores fuera delInteger
rango) oRational
s (cuando se rastrean nanosegundos)):En otras palabras, hasta donde yo entiendo,
DateTime
ya no cubre un rango más amplio de valores potenciales queTime
.Además,
DateTime
probablemente deberían tenerse en cuenta dos restricciones no mencionadas anteriormente :Primero,
DateTime
no tiene concepto de segundos intercalares:Para que funcione el ejemplo anterior
Time
, el sistema operativo debe admitir segundos bisiestos y la información de la zona horaria debe configurarse correctamente, por ejemplo, a través deTZ=right/UTC irb
(en muchos sistemas Unix).En segundo lugar,
DateTime
tiene una comprensión muy limitada de las zonas horarias y, en particular, no tiene un concepto de horario de verano . Prácticamente maneja zonas horarias como simples compensaciones UTC + X:Esto puede causar problemas cuando las horas se ingresan como DST y luego se convierten en una zona horaria que no es DST sin realizar un seguimiento de las compensaciones correctas fuera de
DateTime
sí mismo (muchos sistemas operativos ya pueden ocuparse de esto por usted).En general, diría que hoy en día
Time
es la mejor opción para la mayoría de las aplicaciones.También tenga en cuenta una diferencia importante en la suma: cuando agrega un número a un objeto Time, se cuenta en segundos, pero cuando agrega un número a DateTime, se cuenta en días.
fuente
Time
tampoco tiene un concepto de segundos intercalares, por lo que no es diferente deDateTime
. No sé dónde ejecutó sus ejemplos, pero lo intentéTime.new(2012,6,30,23,59,60,0)
en diferentes versiones de Ruby, de 2.0 a 2.7, y siempre lo obtuve2012-07-01 00:00:00 +0000
.Time
admite segundos intercalares o no, depende de la configuración de su sistema operativo y zona horaria. Por ejemplo:TZ=right/UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'
=>2012-06-30 23:59:60 +0000
mientras queTZ=UTC ruby -e 'p Time.new(2012,6,30,23,59,60,0)'
=>2012-07-01 00:00:00 +0000
.Creo que la respuesta a "cuál es la diferencia" es una de las desafortunadas respuestas comunes a esta pregunta en las bibliotecas estándar de Ruby: las dos clases / libs fueron creadas de manera diferente por diferentes personas en diferentes momentos. Es una de las desafortunadas consecuencias de la naturaleza comunitaria de la evolución de Ruby en comparación con el desarrollo cuidadosamente planificado de algo como Java. Los desarrolladores quieren una nueva funcionalidad pero no quieren pisar las API existentes, por lo que solo crean una nueva clase; para el usuario final no hay una razón obvia para que existan las dos.
Esto es cierto para las bibliotecas de software en general: a menudo la razón por la que algún código o API es la forma en que resulta ser histórica en lugar de lógica.
La tentación es comenzar con DateTime porque parece más genérico. Fecha ... y hora, ¿verdad? Incorrecto. El tiempo también mejora las fechas, y de hecho puede analizar zonas horarias donde DateTime no puede. También se desempeña mejor.
Terminé usando el tiempo en todas partes.
Sin embargo, para estar seguro, tiendo a permitir que los argumentos de DateTime se pasen a mis API Timey, y convertirlos. Además, si sé que ambos tienen el método que me interesa, acepto cualquiera de ellos, como este método que escribí para convertir tiempos a XML (para archivos XMLTV)
fuente
Time.new(2011, 11, 1, 10, 30)
produce2011-11-01 10:30:00 +0700
mientrasDateTime.new(2011, 11, 1, 10, 30)
produceTue, 01 Nov 2011 10:30:00 +0000
.Descubrí que cosas tales como analizar y calcular el inicio / final de un día en diferentes zonas horarias son más fáciles de hacer con DateTime, suponiendo que esté utilizando las extensiones ActiveSupport .
En mi caso, necesitaba calcular el final del día en la zona horaria de un usuario (arbitraria) en función de la hora local del usuario que recibí como una cadena, por ejemplo, "2012-10-10 10:10 +0300"
Con DateTime es tan simple como
Ahora intentemos de la misma manera con Time:
En realidad, Time necesita saber la zona horaria antes de analizar (también tenga en cuenta que
Time.zone.parse
noTime.parse
):Entonces, en este caso, definitivamente es más fácil usar DateTime.
fuente
DateTime.parse('2014-03-30 01:00:00 +0100').end_of_day
produceSun, 30 Mar 2014 23:59:59 +0100
, peroTime.zone = 'CET'; Time.zone.parse('2014-03-30 01:00:00').end_of_day
produceSun, 30 Mar 2014 23:59:59 CEST +02:00
(CET = + 01: 00, CEST = + 02: 00 - observe que el desplazamiento ha cambiado). Pero para hacer esto, necesita más información sobre la zona horaria del usuario (no solo la compensación sino también si se usa el ahorro de tiempo).Time.zone.parse
es muy útil al analizar los tiempos con diferentes zonas: te obliga a pensar qué zona deberías usar. A veces, Time.find_zone funciona aún mejor.DateTime
el desplazamiento que le diste, que fue +0100. No proporcionóTime
un desplazamiento, pero una zona horaria ("CET" no describe un desplazamiento, es el nombre de una zona horaria). Las zonas horarias pueden tener diferentes compensaciones durante todo el año, pero una compensación es una compensación y siempre es la misma.Considere cómo manejan las zonas horarias de manera diferente con instancias personalizadas:
Esto puede ser complicado al crear rangos de tiempo, etc.
fuente
Parece que en algunos casos el comportamiento es muy diferente:
fuente
Date
(como era de esperar) analiza solo las fechas, y cuandoDate
se convierte aTime
, siempre usa la medianoche en la zona horaria local como la hora. La diferencia entreTime
y seTimeDate
deriva del hecho de queTime
no comprende BST, lo cual es sorprendente, dado que las zonas horarias generalmente se manejan más correctamenteTime
(con respecto al horario de verano, por ejemplo). Entonces, en este caso, soloDateTime
analiza la cadena completa correctamente.Además de la respuesta de Niels Ganser , podría considerar este argumento:
Tenga en cuenta que la Guía de estilo Ruby establece claramente una posición al respecto:
fuente