2010-11-12 11 views
11

Gli aiutanti di data/ora di Ruby sono utili ma ho trovato una discrepanza. Sembra che 12. mesi non sia uguale a 1.anno. Controlla 1.month e troverai che è uguale a 30.days e, naturalmente, 12 * 30.days = 360.days, a 5,25 giorni da una durata effettiva di un anno.In Ruby, 12. mesi! = 1.anno

Mi sono imbattuto in questo quando ho impostato l'accesso a determinati componenti del nostro sito web in base al numero di mesi concesso, come specificato dal cliente. Ho scoperto che un periodo di 36 mesi è scaduto un paio di settimane prima quando ho eseguito i miei test. La soluzione è stata qualcosa di simile:

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

Questo restituisce il numero di secondi in qualsiasi frazione di un anno è rappresentato dai NUMBER_OF_MONTHS.

Poiché 1.anno è uguale in secondi a 365,25 giorni, perché si suppone che non abbiano 1.month restituire i secondi per 1/12 di un anno anziché 30 giorni?

Qualcuno ha incontrato prima questo? Qualcuno ha una soluzione migliore?

+3

Non correlato, ma non è necessario che la chiamata 'to_f' in là; basta dividere per '12.0'. –

risposta

24

Il calendario, e il tempo in generale, è una cosa così arbitraria ed è pieno di incongruenze come questa. Non esiste una durata standard di "mese", in quanto la variazione è compresa tra 28 e 31 giorni, così come non esiste una lunghezza standard di "giorno", che può essere ovunque da 23 a 25 ore, e anche un minuto può avere ovunque da Da 59 a 62 secondi quando si tiene conto dei "secondi bisestili". Allo stesso modo un anno può essere 365 o 366 giorni, o anche 351 come nel 1582.

A meno che non si stiano facendo calcoli specifici per un intervallo particolare, come il numero di secondi tra il 3 gennaio 2010 e il 19 ottobre, Nel 2011, non sarai in grado di sapere per quanto tempo l'intervallo utilizza mesi, giorni o anni astratti. Queste cose dipendono da un numero enorme di fattori.

La tua soluzione è adatta per la tua applicazione, ma in termini di Rails un "mese" è di soli 30 giorni per semplicità, proprio come un "giorno" è di 24 ore.

+3

+ 1 per questo. Ci siamo imbattuti in problemi simili come OP quando codificavano alcune logiche per la nostra app. Fondamentalmente devi capire che quelle unità di tempo sfortunatamente non si allineano per la loro stessa natura, quindi se stai facendo conversioni settimanali, calcoli mensili o qualcosa del genere, devi solo accettare che le cose saranno un approssimazione e utilizzare un metodo di conversione coerente (ad esempio, convertire sempre al numero di giorni prima) – Jeremy

+1

È triste che un secondo non sia nemmeno più di 1/60 di minuto. Dang quegli atomi di cesio e più veloce del viaggio leggero. –

0

1 anno è composto da 12 mesi singoli, ma molti di questi mesi sono di dimensioni diverse. Dato che un mese potrebbe effettivamente essere 28, 29, 30 o 31 giorni di calendario, è ragionevole aspettarsi che qualsiasi definizione data della lunghezza di un mese non sia quella che si vuole.

Personalmente, nella maggior parte dei casi, utilizzo 4 settimane come definizione di un mese. In questo caso, dove concedi l'accesso per "un mese", sarei propenso a memorizzare il giorno del mese in cui è stato concesso l'accesso. Quindi, prendi il numero del mese e metti la scadenza lo stesso giorno del mese N numeri del mese dopo.

+0

In altre parole, non utilizzare la/lunghezza/del mese per qualcosa; usa il numero del mese. – dannysauer

0
require 'date' 

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

Se si vuole sottrarre mesi, utilizzare < <.

8

Sì e no:

12 months sono le stesse di 1 year quando li usate come intervalli relativi, perché non sono convertite in secondi poi:

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

Internamente, questi intervalli sono tenuti come array del numero di anni, mesi e giorni, quindi se si dice, per esempio:

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

significa che la sottrazione produce un intervallo composto da "un anno e meno 12 mesi".

Ma se si to_i loro, hanno bisogno di essere convertiti in un numero esatto di secondi, e qualcuno ha deciso che "un mese" significa "30 giorni", che è la migliore approssimazione di qualsiasi altro, mentre si bastone con esso.

che è sottolineato nella documentazione:

Mentre questi metodi forniscono precisi calcolo quando viene utilizzato come negli esempi di cui sopra, si deve prestare attenzione notare che questo non è vero se il risultato di 'mesi', 'anni', etc è convertito prima dell'uso

Credo che questi intervalli possono essere visto come "pigramente valutata" in un certo senso.

Problemi correlati