webentwicklung-frage-antwort-db.com.de

Unterschied zwischen DateTime und Zeit in Ruby

Was ist der Unterschied zwischen DateTime- und Time-Klassen in Ruby und welche Faktoren würden mich veranlassen, die eine oder die andere zu wählen?

204
Tom Lehman

Neuere Versionen von Ruby (2.0+) weisen nicht wirklich signifikante Unterschiede zwischen den beiden Klassen auf. Einige Bibliotheken verwenden die eine oder andere aus historischen Gründen, aber neuer Code muss nicht unbedingt betroffen sein. Es ist wahrscheinlich am besten, eine für Konsistenz zu wählen. Versuchen Sie daher, die Erwartungen Ihrer Bibliotheken zu erfüllen. Beispielsweise bevorzugt ActiveRecord DateTime.

In Versionen vor Ruby 1.9 und auf vielen Systemen wird Time als vorzeichenbehafteter 32-Bit-Wert dargestellt, der die Anzahl der Sekunden seit dem 1. Januar 1970, UTC, als dünnen Wrapper um einen POSIX-Standard-time_t-Wert beschreibt.

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

Neuere Versionen von Ruby können größere Werte ohne Fehler verarbeiten.

DateTime ist ein kalenderbasierter Ansatz, bei dem Jahr, Monat, Tag, Stunde, Minute und Sekunde einzeln gespeichert werden. Dies ist ein Ruby on Rails-Konstrukt, das als Wrapper für SQL-Standard-DATETIME-Felder dient. Diese enthalten beliebige Datumsangaben und können nahezu jeden Zeitpunkt darstellen, da der Ausdrucksbereich normalerweise sehr groß ist.

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

Es ist also beruhigend, dass DateTime Blog-Beiträge von Aristoteles verarbeiten kann.

Bei der Auswahl sind die Unterschiede jetzt etwas subjektiv. In der Vergangenheit hat DateTime bessere Optionen für die Bearbeitung auf kalendarische Weise zur Verfügung gestellt, aber viele dieser Methoden wurden zumindest in der Rails-Umgebung auch auf Time portiert.

168
tadman

[Bearbeiten Juli 2018]

In Ruby 2.5.1 gilt alles weiterhin. Aus der Referenzdokumentation :

DateTime berücksichtigt keine Schaltsekunden, erfasst keine Sommerzeitregeln.

Was in diesem Thread zuvor nicht erwähnt wurde, ist einer der wenigen Vorteile von DateTime: Es kennt Kalenderreformen, während Time nicht:

[…] Rubys Time-Klasse implementiert einen proleptischen Gregorianischen Kalender und hat kein Konzept der Kalenderreform […].

Die Referenzdokumentation schließt mit der Empfehlung ab, Time zu verwenden, wenn ausschließlich aus vergangenen, aktuellen oder zukünftigen Datumsangaben gearbeitet wird, und DateTime nur dann zu verwenden, wenn der Geburtstag von Shakespeare genau konvertiert werden muss: (Hervorhebung hinzugefügt)

Wann sollten Sie DateTime in Ruby und wann sollten Sie Time verwenden? Wahrscheinlich möchten Sie Time verwenden, da Ihre App wahrscheinlich aktuelle Daten und Zeiten verarbeitet. Wenn Sie jedoch mit Datum und Uhrzeit in einem historischen Kontext umgehen müssen, sollten Sie DateTime […] verwenden. Wenn Sie auch mit Zeitzonen zu tun haben, dann viel Glück - denken Sie daran, dass Sie sich wahrscheinlich mit lokalen Sonnenzeiten befassen werden, da die Einführung der Eisenbahnen erst im 19. Jahrhundert Standardzeit erforderlich machte und schließlich Zeitzonen.

[/ Juli 2018 bearbeiten]

Seit Ruby 2.0 sind die meisten Informationen in den anderen Antworten nicht mehr aktuell.

Insbesondere ist Time jetzt praktisch ungebunden. Es kann mehr oder weniger als 63 Bits von Epoche entfernt sein:

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

Die einzige Konsequenz bei der Verwendung größerer Werte sollte die Leistung sein. Dies ist besser, wenn Integers verwendet wird (vs. Bignums (Werte außerhalb des Integer-Bereichs) oder Rationals (wenn Nanosekunden verfolgt werden)):

Seit Ruby 1.9.2 verwendet die Time-Implementierung eine 63-Bit-Ganzzahl mit Vorzeichen, Bignum oder Rational. Die ganze Zahl ist eine Anzahl von Nanosekunden seit der Epoche, die 1823-11-12 bis 2116-02-20 darstellen kann. Wenn Bignum oder Rational verwendet wird (vor 1823, nach 2116 unter einer Nanosekunde), arbeitet Time langsamer als bei Verwendung der Ganzzahl . ( http://www.Ruby-doc.org/core-2.1.0/Time.html )

Mit anderen Worten, soweit ich das verstehe, deckt DateTime NICHT MEHR EINEN GRÖSSEREN BEREICH POTENTIELLER WERTE AB ALS Time.

Darüber hinaus sind wahrscheinlich zwei zuvor nicht erwähnte Einschränkungen von DateTime zu beachten:

DateTime berücksichtigt keine Schaltsekunden, verfolgt keine Sommerzeitregeln . ( http://www.Ruby-doc.org/stdlib-2.1.0/libdoc/date/rdoc/Date.html#class-Date-label-DateTime )

Erstens hat DateTime kein Konzept von Schaltsekunden:

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

Zweitens hat DateTime ein sehr begrenztes Verständnis von Zeitzonen und insbesondere hat kein Sommerzeitkonzept. Es behandelt Zeitzonen praktisch als einfache UTC + X-Offsets:

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>

Dies kann zu Problemen führen, wenn Zeiten als DST eingegeben und dann in eine Nicht-DST-Zeitzone konvertiert werden, ohne die korrekten Offsets außerhalb von DateTime selbst zu verfolgen (viele Betriebssysteme kümmern sich möglicherweise bereits darum).

Insgesamt würde ich sagen, dass heutzutage Time für die meisten Anwendungen die bessere Wahl ist.

Beachten Sie auch einen wichtigen Unterschied beim Hinzufügen: Wenn Sie einem Time-Objekt eine Zahl hinzufügen, wird dies in Sekunden gezählt, aber wenn Sie einer DateTime eine Zahl hinzufügen, wird sie in Tagen gezählt.

88
Niels Ganser

Überholt! Siehe unten...

Der Leistungsunterschied kann nicht genug betont werden ... Zeit ist C und DateTime ist 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)

Update (2/2012):

Wie bereits erwähnt, hat 1.9.3 die Leistung von DateTime erheblich verbessert:

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

Ich denke, die Antwort auf "Was ist der Unterschied" ist eine der unglücklichen allgemeinen Antworten auf diese Frage in den Ruby-Standardbibliotheken: Die beiden Klassen/Bibliotheken wurden von verschiedenen Personen zu unterschiedlichen Zeitpunkten unterschiedlich erstellt. Dies ist eine der unglücklichen Folgen der gemeinschaftlichen Natur von Rubys Evolution im Vergleich zu einer sorgfältig geplanten Entwicklung von so etwas wie Java. Entwickler wünschen sich neue Funktionen, wollen aber nicht auf vorhandene APIs zugreifen, sondern erstellen einfach eine neue Klasse. Für den Endbenutzer gibt es keinen offensichtlichen Grund, warum die beiden existieren.

Dies gilt im Allgemeinen für Softwarebibliotheken: Oft ist der Grund, warum Code oder API so ist, dass er historisch und nicht logisch ist.

Die Versuchung besteht darin, mit DateTime zu beginnen, da es allgemeiner erscheint. Datum ... und Uhrzeit, richtig? Falsch. Die Zeit ist auch besser für Datumsangaben und kann auch Zeitzonen analysieren, in denen DateTime nicht möglich ist. Es funktioniert auch besser.

Ich habe überall Zeit verwendet.

Um sicherzugehen, neige ich dazu, DateTime-Argumente in meine Timey-APIs zu übergeben und beide zu konvertieren. Auch wenn ich weiß, dass beide die Methode haben, die mich interessiert, akzeptiere ich auch, wie diese Methode, die ich für die Konvertierung in XML geschrieben habe (für XMLTV-Dateien).

# 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
43
Rhubarb

Ich habe festgestellt, dass solche Dinge wie das Analysieren und Berechnen des Beginns/Endes eines Tages in verschiedenen Zeitzonen mit DateTime einfacher sind, vorausgesetzt, Sie verwenden die ActiveSupport-Erweiterungen .

In meinem Fall musste ich das Ende des Tages in der Zeitzone eines Benutzers (willkürlich) basierend auf der Ortszeit des Benutzers berechnen, die ich als Zeichenfolge erhielt, z. "2012-10-10 10:10 +0300"

Mit DateTime ist es so einfach wie 

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

Versuchen wir es auf dieselbe Weise mit der Zeit:

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.

Eigentlich muss Time die Zeitzone kennen, bevor sie analysiert wird (beachten Sie, dass es Time.zone.parse ist, nicht 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

In diesem Fall ist es also definitiv einfacher, DateTime zu verwenden.

9

Überlegen Sie, wie sie mit benutzerdefinierten Instantiierungen unterschiedlich mit Zeitzonen umgehen:

irb(main):001:0> Time.new(2016,9,1)
=> 2016-09-01 00:00:00 -0400
irb(main):002:0> DateTime.new(2016,9,1)
=> Thu, 01 Sep 2016 00:00:00 +0000
irb(main):003:0> Time.new(2016,9,1).to_i
=> 1472702400
irb(main):004:0> DateTime.new(2016,9,1).to_i
=> 1472688000

Dies kann bei der Erstellung von Zeiträumen usw. schwierig sein.

4
gr8scott06

Es scheint, dass das Verhalten in einigen Fällen sehr unterschiedlich ist:

Time.parse("Ends from 28 Jun 2018 12:00 BST").utc.to_s

"2018-06-28 09:00:00 UTC"

Date.parse("Ends from 28 Jun 2018 12:00 BST").to_time.utc.to_s

"2018-06-27 21:00:00 UTC"

DateTime.parse("Ends from 28 Jun 2018 12:00 BST").to_time.utc.to_s

"2018-06-28 11:00:00 UTC"

0
Alexey Strizhak