2010-11-12 5 views
11

Rubys Datum/Zeit Helfer sind nützlich, aber ich fand eine Diskrepanz. Es scheint, dass 12.Monat nicht gleich 1.Jahr ist. Überprüfen Sie 1.Monat und Sie werden feststellen, es ist gleich 30.days und natürlich 12 * 30.Tage = 360.Tage, 5,25 Tage kurz vor einem tatsächlichen Jahreslänge.In Ruby, 12.Monate! = 1.Jahr

Ich bin darauf gestoßen, als ich den Zugriff auf bestimmte Komponenten unserer Website basierend auf der Anzahl der Monate, die gewährt wurden, wie vom Kunden angegeben, festgelegt. Ich entdeckte, dass eine 36. Monatsfrist einige Wochen zu früh ablief, wenn ich meine Tests durchführte. Die Lösung war so etwas wie diese:

def months_to_seconds(number_of_months) 
    ((number_of_months.to_f/12) * 1.year).to_i.seconds 
end 

Dies gibt die Anzahl der Sekunden in was auch immer Bruchteil eines Jahres durch die NUMBER_OF_MONTHS vertreten ist.

Seit 1.Jahr ist gleich in 365.25 Tage, warum glauben Sie, sie hatten nicht 1.Monat die Sekunden für 1/12 eines Jahres anstelle von 30 Tagen zurückgeben?

Hat jemand schon mal darüber gelaufen? Hat jemand eine bessere Lösung?

+3

Unrelated, aber Sie brauchen nicht, dass 'to_f' dort zu nennen; dividiere einfach durch '12.0'. –

Antwort

24

Der Kalender und die Zeit im Allgemeinen ist so eine willkürliche Sache und ist mit Inkonsistenzen wie diese gespickt. Es gibt keine Standardlänge von "Monat", da die Variation irgendwo zwischen 28 und 31 Tagen liegt, genauso wie es keine Standardlänge von "Tag" gibt, die irgendwo zwischen 23 und 25 Stunden liegen kann, und sogar die Minute kann irgendwo von haben 59 bis 62 Sekunden, wenn "Schaltsekunden" berücksichtigt werden. Ebenso kann ein Jahr 365 oder 366 Tage oder sogar 351 sein, wie es 1582 der Fall war.

Sofern Sie nicht für ein bestimmtes Intervall spezifische Berechnungen durchführen, wie die Anzahl der Sekunden zwischen dem 3. Januar 2010 und dem 19. Oktober, 2011 werden Sie nicht wissen können, wie lange das Intervall abstrakte Monate, Tage oder Jahre verwendet. Diese Dinge hängen von einer Vielzahl von Faktoren ab.

Ihre Lösung ist für Ihre Anwendung geeignet, aber in den Rails-Bedingungen ist ein "Monat" einfach 30 Tage der Einfachheit halber, genauso wie ein "Tag" 24 Stunden ist.

+3

+ 1 dafür. Bei der Codierung einiger Logik für unsere App stießen wir auf ähnliche Probleme wie OP. Im Grunde müssen Sie erkennen, dass diese Zeiteinheiten sich leider aufgrund ihrer Natur nicht aufstellen lassen. Wenn Sie also Konvertierungen zwischen wöchentlichen, monatlichen Berechnungen oder so machen, müssen Sie einfach akzeptieren, dass die Dinge ein sein werden Approximation und verwenden Sie eine konsistente Konvertierungsmethode (z. B. immer zuerst in eine Anzahl von Tagen konvertieren) – Jeremy

+1

Es ist traurig, dass eine Sekunde nicht einmal 1/60 Minute mehr ist. Dang diese Cäsiumatome und schneller als Licht reisen. –

0

1 Jahr besteht aus 12 einzelnen Monaten, aber mehrere dieser Monate haben unterschiedliche Größen. Da ein Monat tatsächlich 28, 29, 30 oder 31 Kalendertage betragen kann, ist es vernünftig zu erwarten, dass eine gegebene Definition der Länge eines Monats möglicherweise nicht das ist, was man möchte.

Persönlich verwende ich 4 Wochen als die Definition eines Monats in den meisten Fällen. In diesem Fall, in dem Sie den Zugriff für "einen Monat" gewähren, würde ich geneigt sein, den Tag des Monats zu speichern, auf den der Zugriff gewährt wurde. Dann nimm die Monatsnummer und setze den Ablauf am selben Tag des Monats N Monat-Nummern später.

+0

Mit anderen Worten, verwenden Sie nicht die/Länge/des Monats für irgendetwas; Verwende die Nummer des Monats. – dannysauer

0
require 'date' 

expire_date = Date.today >> 36 
puts expire_date #=> 2013-11-12 

Wenn Sie Monate subtrahieren, verwenden < <.

8

Ja und nein:

12 months sind die gleichen wie 1 year, wenn man sie als relative Intervalle verwendet werden, da sie dann nicht in Sekunden umgewandelt werden:

t = Time.now 
#=> 2010-11-12 22:34:57 0100 
t - 1.year == t - 12.months 
#=> true 

Intern werden diese Intervalle werden als Arrays gehalten die Anzahl der Jahre, Monate und Tage, also, wenn Sie sagen, zum Beispiel:

1.year - 12.months 
#=> 1 year and -12 months 

bedeutet dies, dass die Subtraktion in einer Folge Intervall bestehend aus "einem Jahr und minus 12 Monaten".

Aber wenn Sie to_i ihnen, müssen sie auf die genaue Anzahl von Sekunden konvertiert werden, und jemand entschied, dass "ein Monat" bedeutet "30 Tage", die eine gute Näherung als alle anderen ist, während Sie dabei bleiben.

, die in der Dokumentation darauf hingewiesen hat:

Während diese Verfahren eine präzise Berechnung, wenn, wie in den obigen Beispielen verwendet, Pflege ergriffen werden sollten, zu beachten, dass dies nicht wahr ist, wenn das Ergebnis ‚Monate‘, ‚Jahr‘, etc. wird vor der Verwendung umgewandelt

ich denke, diese Intervalle betrachtet werden können als „faul ausgewertet“ in einer Art und Weise.