2010-11-12 8 views
11

Los ayudantes de fecha/hora de Ruby son útiles, pero encontré una discrepancia. Parece que 12. meses no es igual a 1. años. Verifique 1.month y encontrará que es igual a 30.days y, por supuesto, 12 * 30.days = 360.days, 5.25 días menos que la duración real de un año.En Ruby, 12.months! = 1.year

Me encontré con esto cuando establecí el acceso a ciertos componentes de nuestro sitio web en función del número de meses concedidos, según lo especificado por el cliente. Descubrí que un término de 36 meses expiró un par de semanas antes al ejecutar mis pruebas. La solución fue algo como esto:

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

Esto devuelve el número de segundos en cualquier fracción de un año está representado por los NUMBER_OF_MONTHS.

Como 1.year es igual en segundos a 365.25 días, ¿por qué supones que no tienen 1.meses para devolver los segundos para 1/12 de un año en lugar de 30 días?

¿Alguien ha encontrado esto antes? ¿Alguien tiene una solución mejor?

+3

No relacionado, pero no necesita esa llamada 'to_f'; solo divida por '12.0'. –

Respuesta

24

El calendario, y el tiempo en general, es algo tan arbitrario y está plagado de inconsistencias como esta. No hay una duración estándar de "mes", ya que la variación oscila entre 28 y 31 días, del mismo modo que no existe una duración estándar de "día", que puede ser de 23 a 25 horas, e incluso minutos puede tener desde 59 a 62 segundos cuando se tienen en cuenta los "segundos intercalares". Del mismo modo, un año puede ser 365 o 366 días, o incluso 351 como en 1582.

A menos que esté haciendo cálculos específicos para un intervalo particular, como el número de segundos entre el 3 de enero de 2010 y el 19 de octubre. 2011, no podrá saber por cuánto tiempo el intervalo usa meses, días o años abstractos. Estas cosas dependen de una gran cantidad de factores.

Su solución es adecuada para su aplicación, pero en términos de Rails, un "mes" es simplemente 30 días por simplicidad, al igual que un "día" es de 24 horas.

+3

+ 1 para esto. Nos encontramos con problemas similares a los de OP al codificar cierta lógica para nuestra aplicación. Básicamente hay que darse cuenta de que esas unidades de tiempo lamentablemente no se alinean debido a su propia naturaleza, por lo que si está haciendo conversiones entre semana, cálculos mensuales o algo así, simplemente tendrá que aceptar que las cosas serán una aproximación y uso de un método de conversión consistente (por ejemplo, siempre conviértalo primero al número de días) – Jeremy

+1

Es triste que un segundo ya no sea 1/60 de minuto más. Dang esos átomos de cesio y más rápido que la luz de viaje. –

0

1 año se compone de 12 meses individuales, pero varios de esos meses son de diferentes tamaños. Dado que un mes podría ser en realidad de 28, 29, 30 o 31 días calendario, es razonable esperar que una definición dada de la duración de un mes no sea lo que uno desea.

Personalmente, utilizo 4 semanas como la definición de un mes en la mayoría de los casos. En este caso, cuando otorgue acceso por "un mes", me inclinaría por almacenar el día del mes en que se otorgó el acceso. Luego, tome el número del mes y ponga el vencimiento el mismo día del mes, los números del mes N más adelante.

+0

En otras palabras, no use/length/of the month para nada; usa el número del mes. – dannysauer

0
require 'date' 

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

Si desea restar meses, utilizar < <.

8

Sí y no:

12 months son los mismos que 1 year cuando los utiliza como intervalos relativos, debido a que no se convierten en segundos, entonces:

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

Internamente, estos intervalos se mantienen como matrices del número de años, meses y días, así que si usted dice, por ejemplo:

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

significa que la sustracción dio lugar a una intervalo que consiste en "un año y menos 12 meses".

Pero si los to_i, se deben convertir a la cantidad exacta de segundos, y alguien decidió que "un mes" significa "30 días", lo cual es una buena aproximación, mientras se mantiene.

la que apuntaba a cabo en la documentación:

Si bien estos métodos proporcionan cálculo preciso cuando se utiliza como en los ejemplos anteriores, se debe tener cuidado tener en cuenta que esto no es cierto si el resultado de 'meses', 'años', etc se convertidos antes de su uso

supongo que estos intervalos pueden ser vistos como "pereza evaluado" en cierto modo.

Cuestiones relacionadas