242 votes

Différence entre DateTime et Time en Ruby

Quelle est la différence entre DateTime y Time en Ruby et quels facteurs me feraient choisir l'un ou l'autre ?

0 votes

La docs a une section en expliquant quand et comment les utiliser.

186voto

tadman Points 70178

Les versions plus récentes de Ruby (2.0+) ne présentent pas vraiment de différences significatives entre les deux classes. Certaines bibliothèques utiliseront l'une ou l'autre pour des raisons historiques, mais le nouveau code ne doit pas nécessairement s'en préoccuper. Il est probablement préférable d'en choisir une pour des raisons de cohérence, alors essayez de vous adapter aux attentes de vos bibliothèques. Par exemple, ActiveRecord préfère DateTime.

Dans les versions antérieures à Ruby 1.9 et sur de nombreux systèmes, le temps est représenté sous la forme d'une valeur signée de 32 bits décrivant le nombre de secondes écoulées depuis le 1er janvier 1970 UTC, une enveloppe fine autour d'un standard POSIX time_t et est borné :

Time.at(0x7FFFFFFF)
# => Mon Jan 18 22:14:07 -0500 2038
Time.at(-0x7FFFFFFF)
# => Fri Dec 13 15:45:53 -0500 1901

Les versions plus récentes de Ruby sont capables de gérer des valeurs plus importantes sans produire d'erreurs.

DateTime est une approche basée sur le calendrier où l'année, le mois, le jour, l'heure, la minute et la seconde sont stockés individuellement. Il s'agit d'une construction Ruby on Rails qui sert d'enveloppe aux champs DATETIME standard de SQL. Ceux-ci contiennent des dates arbitraires et peuvent représenter presque n'importe quel moment dans le temps, car la plage d'expression est généralement très large.

DateTime.new
# => Mon, 01 Jan -4712 00:00:00 +0000

Il est donc rassurant de savoir que DateTime peut gérer les articles de blog d'Aristote.

Au moment d'en choisir un, les différences sont désormais quelque peu subjectives. Historiquement, DateTime offre de meilleures options pour la manipulation des données sous forme de calendrier, mais nombre de ces méthodes ont également été transférées à Time, du moins dans l'environnement Rails.

6 votes

Dois-je donc toujours utiliser DateTime ?

4 votes

Si vous travaillez avec des dates, je dirais qu'il faut utiliser DateTime. Time est pratique pour représenter des choses comme l'heure actuelle de la journée, ou des points dans un futur proche comme 10.minutes.from_now. Les deux ont beaucoup en commun, bien que, comme indiqué, DateTime puisse représenter un éventail de valeurs beaucoup plus large.

0 votes

> Le temps est pratique pour représenter des choses telles que l'heure actuelle de la journée, ou des points dans un futur proche tels que 10.minutes.from_now. Pourquoi Time est-il plus pratique que DateTime à cette fin ?

113voto

Niels Ganser Points 341

Comme de ruby 2.0, la plupart des renseignements ci-dessus est hors de date.

En particulier, Time est maintenant pratiquement indépendant. Elle peut être plus ou moins de même 63 bits loin de l'Époque:

irb(main):001:0> RUBY_VERSION
=> "2.0.0"
irb(main):002:0> Time.at(2**62-1).utc # within Integer range
=> 146138514283-06-19 07:44:38 UTC
irb(main):003:0> Time.at(2**128).utc # outside of Integer range
=> 10783118943836478994022445751222-08-06 08:03:51 UTC
irb(main):004:0> Time.at(-2**128).utc # outside of Integer range
=> -10783118943836478994022445747283-05-28 15:55:44 UTC

La seule conséquence de l'utilisation de plus grandes valeurs de performance, ce qui est mieux quand Integers sont utilisés (contre Bignums (valeurs en dehors de l' Integer de la gamme) ou Rationals (lorsque nanosecondes sont suivis)):

Depuis Ruby 1.9.2, le Temps de la mise en œuvre utilise un signé 63 bits entier, Bignum ou Rationnelle. Le nombre entier est un nombre de nanosecondes depuis l'Époque ce qui peut représenter 1823-11-12 à 2116-02-20. Lorsque Bignum ou Rationnel est utilisé (avant 1823, après 2116, en vertu de l'ordre de la nanoseconde), le Temps plus lentement que lors de l'entier est utilisé. (http://www.ruby-doc.org/core-2.1.0/Time.html)

En d'autres termes, comme je le comprends, DateTime plus couvre un plus large éventail de valeurs possibles que Time.

En outre, deux précédemment sous silence les restrictions d' DateTime devrait probablement être noté:

DateTime ne considère aucun leapseconds, ne pas suivre tout l'été règles de temps. (http://www.ruby-doc.org/stdlib-2.1.0/libdoc/date/rdoc/Date.html#class-Date-label-DateTime)

Tout d'abord, DateTime n'a pas de notion de secondes intercalaires:

irb(main):001:0> RUBY_VERSION
=> "2.0.0"
irb(main):002:0> require "date"
=> true
irb(main):003:0> t = Time.new(2012,6,30,23,59,60,0)
=> 2012-06-30 23:59:60 +0000
irb(main):004:0> dt = t.to_datetime; dt.to_s
=> "2012-06-30T23:59:59+00:00"
irb(main):005:0> t == dt.to_time
=> false
irb(main):006:0> t.to_i
=> 1341100824
irb(main):007:0> dt.to_i
=> 1341100823

Deuxièmement, DateTime a une compréhension très limitée des zones de temps et, en particulier, n'a aucune notion de l'heure d'été. Il gère les fuseaux horaires comme simple UTC + X décalages:

irb(main):001:0> RUBY_VERSION
=> "2.0.0"
irb(main):002:0> require "date"
=> true
irb(main):003:0> t = Time.local(2012,7,1)
=> 2012-07-01 00:00:00 +0200
irb(main):004:0> t.zone
=> "CEST"
irb(main):005:0> t.dst?
=> true
irb(main):006:0> dt = t.to_datetime; dt.to_s
=> "2012-07-01T00:00:00+02:00"
irb(main):007:0> dt.zone
=> "+02:00"
irb(main):008:0> dt.dst?
NoMethodError: undefined method `dst?' for #<DateTime:0x007f34ea6c3cb8>

Cela peut causer des problèmes lorsque les temps sont entrés comme de l'heure d'été, puis converti en une non-de l'heure d'été de fuseau horaire, sans garder une trace de l'corriger les décalages à l'extérieur de l' DateTime lui-même (de nombreux systèmes d'exploitation peuvent déjà prendre soin de cela pour vous).

Dans l'ensemble, je dirais que de nos jours, Time est le meilleur choix pour la plupart des applications.

0 votes

Est-ce encore vrai en 2018 ?

2 votes

C'est toujours vrai dans Ruby 2.5.1. ruby-doc.org/stdlib-2.5.1/libdoc/date/rdoc/DateTime.html : "DateTime ne prend en compte aucune seconde intercalaire, ne suit aucune règle d'heure d'été". Cependant, notez que DateTime a des avantages lorsque vous devez traiter des dates/heures du calendrier pré-grégorien. Cela n'a pas été mentionné ici auparavant mais est documenté dans la documentation de référence : "[ ] la classe Time de Ruby met en œuvre un calendrier grégorien proleptique et n'a aucun concept de réforme du calendrier [ ]." Je vais éditer ma réponse pour fournir quelques détails supplémentaires.

0 votes

Time n'a pas non plus de concept de secondes intercalaires, il n'est donc pas différent de DateTime . Je ne sais pas où vous avez exécuté vos exemples, mais j'ai essayé Time.new(2012,6,30,23,59,60,0) dans différentes versions de Ruby, de la 2.0 à la 2.7, et j'ai toujours obtenu 2012-07-01 00:00:00 +0000 .

66voto

Mladen Jablanović Points 22082

La différence de performance ne peut être suffisamment soulignée... Time est en C, et DateTime est en Ruby :

>> Benchmark.bm do |bm|
?>   bm.report('DateTime:') do
?>     n1 = DateTime.now
>>     n2 = DateTime.now
>>     1_000_000.times{ n1 < n2 }
>>   end
>>   bm.report('Time:    ') do
?>     n1 = Time.now
>>     n2 = Time.now
>>     1_000_000.times{ n1 < n2 }
>>   end
>> end
      user     system      total        real
DateTime:  4.980000   0.020000   5.000000 (  5.063963)
Time:      0.330000   0.000000   0.330000 (  0.335913)

Mise à jour (2/2012) :

Comme déjà mentionné dans le commentaire, la 1.9.3 a grandement amélioré DateTime performance :

       user     system      total        real
DateTime:  0.330000   0.000000   0.330000 (  0.333869)
Time:      0.300000   0.000000   0.300000 (  0.306444)

45voto

Rhubarb Points 16453

Je pense que la réponse à la question " quelle est la différence ? " est l'une des réponses malheureusement courantes à cette question dans les bibliothèques standard de Ruby : les deux classes/libs ont été créées différemment par différentes personnes à différents moments. C'est l'une des conséquences malheureuses de la nature communautaire de l'évolution de Ruby par rapport au développement soigneusement planifié de quelque chose comme Java. Les développeurs veulent de nouvelles fonctionnalités mais ne veulent pas empiéter sur les API existantes, alors ils créent simplement une nouvelle classe - pour l'utilisateur final, il n'y a pas de raison évidente pour que les deux classes existent.

Cela vaut pour les bibliothèques de logiciels en général : souvent, la raison pour laquelle un code ou une API est tel qu'il est s'avère être historique plutôt que logique.

La tentation est de commencer par DateTime parce qu'il semble plus générique. Date... et Heure, c'est ça ? Non, c'est faux. Time fait également mieux les dates, et en fait peut analyser les fuseaux horaires là où DateTime ne le peut pas. Il est également plus performant.

J'ai fini par utiliser Time partout.

Par précaution, j'ai tendance à autoriser le passage d'arguments DateTime dans mes API temporelles et à les convertir. De même, si je sais que les deux ont la méthode qui m'intéresse, j'accepte l'une ou l'autre, comme cette méthode que j'ai écrite pour convertir les heures en XML (pour les fichiers 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"
def self.format_date_time(date_time)
  if (date_time.respond_to?(:rfc822)) then
    return format_time(date_time)
  else 
    time = Time.parse(date_time.to_s)
    return format_time(time)
  end    
end

# Note must use a Time, not a String, nor a DateTime, nor Date.
# see format_date_time for the more general version
def self.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 chars
  return "#{time.strftime( '%Y%m%d%H%M%S' )} #{time.rfc822[-5..-1]}"
end

8 votes

En outre, Time.new et DateTime.new traitent le fuseau horaire différemment. Je suis en GMT+7, donc Time.new(2011, 11, 1, 10, 30) produit 2011-11-01 10:30:00 +0700 tandis que DateTime.new(2011, 11, 1, 10, 30) produit Tue, 01 Nov 2011 10:30:00 +0000 .

23 votes

Et comme nous le savons tous, le développement soigneusement planifié de Java a abouti à des API exclusivement simples et logiques.

0 votes

@PhuongNguyen : Pourriez-vous s'il vous plaît ajouter cela comme une réponse afin que je puisse l'up-voter ? C'est précisément la raison pour laquelle j'ai décidé de choisir Time plutôt que DateTime.

10voto

Yuriy Kharchenko Points 421

J'ai trouvé que des choses comme l'analyse et le calcul du début/de la fin d'un jour dans différents fuseaux horaires sont plus faciles à faire avec DateTime, en supposant que vous utilisez les extensions ActiveSupport .

Dans mon cas, j'avais besoin de calculer la fin de la journée dans le fuseau horaire (arbitraire) d'un utilisateur en fonction de l'heure locale de l'utilisateur que j'ai reçue sous forme de chaîne, par exemple "2012-10-10 10:10 +0300".

Avec DateTime, c'est aussi simple que

irb(main):034:0> DateTime.parse('2012-10-10 10:10 +0300').end_of_day
=> Wed, 10 Oct 2012 23:59:59 +0300
# it preserved the timezone +0300

Essayons maintenant de procéder de la même manière avec le temps :

irb(main):035:0> Time.parse('2012-10-10 10:10 +0300').end_of_day
=> 2012-10-10 23:59:59 +0000
# the timezone got changed to the server's default UTC (+0000), 
# which is not what we want to see here.

En fait, Time a besoin de connaître le fuseau horaire avant d'effectuer le parsing (notez aussi que c'est Time.zone.parse pas 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, 10 Oct 2012 23:59:59 EEST +03:00

Dans ce cas, il est donc plus facile d'opter pour DateTime.

1 votes

Vous utilisez cette technique en production maintenant, y a-t-il des inconvénients à cette technique ?

1 votes

DateTime ne tient pas compte de l'heure d'été. Ainsi, au changement d'heure d'été, il ne fonctionnera pas correctement. DateTime.parse('2014-03-30 01:00:00 +0100').end_of_day produit Sun, 30 Mar 2014 23:59:59 +0100 mais Time.zone = 'CET'; Time.zone.parse('2014-03-30 01:00:00').end_of_day produit Sun, 30 Mar 2014 23:59:59 CEST +02:00 (CET=+01:00, CEST=+02:00 - remarquez que le décalage a changé). Mais pour ce faire, vous avez besoin de plus d'informations sur le fuseau horaire de l'utilisateur (pas seulement le décalage mais aussi l'utilisation ou non de l'heure d'été).

1 votes

C'est peut-être une évidence, mais Time.zone.parse es très utile lors de l'analyse d'heures avec différentes zones - cela vous oblige à réfléchir à la zone que vous devriez utiliser. Parfois, Time.find_zone fonctionne encore mieux.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X