2010-10-29 24 views
17

cuando los usuarios se registran en uno de mis sitios para una versión de prueba gratuita, configuro el vencimiento de su cuenta como "14.days.from_now". A continuación, en la página principal muestro el número de días que han restantes, que me sale con:Rails times oddness: "x días a partir de ahora"

(user.trial_expires - Time.now)/86400 

(porque hay 86.400 segundos en un día, es decir, 60 * 60 * 24)

Lo curioso es decir, esto sale como más de 14, por lo que se redondea a 15. En una investigación más a fondo en la consola, esto sucede por solo dos días en el futuro (si sabes a qué me refiero). por ejemplo

>> Time.now 
=> Fri Oct 29 11:09:26 0100 2010 
>> future_1_day = 1.day.from_now 
=> Sat, 30 Oct 2010 11:09:27 BST 01:00 
#ten past eleven tomorrow 

>> (future_1_day - Time.now)/86400 
=> 0.999782301526931 
#less than 1, what you'd expect right? 

>> future_2_day = 2.day.from_now 
=> Sun, 31 Oct 2010 11:09:52 GMT 00:00 
>> (future_2_day - Time.now)/86400 
=> 2.04162248861183 
#greater than 2 - why? 

pensé que tal vez era que ver con las zonas horarias - me di cuenta de que el tiempo de 1.day a partir de ahora se encontraba en BST y el tiempo de 2 días a partir de ahora se encontraba en GMT. ¡Intenté usar localtime y obtuve los mismos resultados!

>> future_2_day = 2.day.from_now.localtime 
=> Sun Oct 31 11:11:24 0000 2010 
>> (future_2_day - Time.now)/86400 
=> 2.04160829127315 
>> (future_2_day - Time.now.localtime)/86400 
=> 2.04058651585648 

entonces me preguntaba qué tan grande es la diferencia, y resulta que es exactamente una hora a cabo. Así que parece una rareza de zona horaria, o al menos algo relacionado con las zonas horarias que no entiendo. Actualmente, mi zona horaria es BST (horario de verano británico), que es una hora más tarde que UTC en este momento (hasta este domingo en cuyo punto vuelve a ser lo mismo que UTC).

Parece que se ha introducido la hora extra cuando agrego dos días a Time.now: mira esto. Empiezo con Time.now, le agrego dos días, resta Time.now, luego restar dos días de segundos del resultado y me queda una hora.

Se me acaba de ocurrir, en una cabeza golpeando momento, que esto está ocurriendo porque el reloj se remontan en el domingo por la mañana: es decir, a las 11.20 de la mañana del domingo que se dos días y una hora más a partir de ahora. Estaba a punto de eliminar toda esta publicación, pero luego me di cuenta de esto: pensé 'ah, puedo arreglar esto usando (24 * daynum) .horas en lugar de daynum.days, pero aún obtengo el mismo resultado: incluso cuando ¡uso segundos!

>> (Time.now + (2*24).hours - Time.now) - 86400*2 
=> 3599.99969500001 
>> (Time.now + (2*24*3600).seconds - Time.now) - 86400*2 
=> 3599.999855 

Así que ahora estoy confundido de nuevo. ¿Cómo puede ahora más dos días en segundos, menos ahora, menos dos días en segundos, una hora en segundos? ¿Dónde entra la hora extra?

+0

Una hora extra podría ser la luz del día ahorrando tal vez? – willcodejavaforfood

+0

No puedo replicar sus resultados. Obtengo '(future_2_day - Time.now)/86400 # => 1.99977137731481'. Estoy en EST (EE. UU.) Y nuestros relojes no vuelven durante este tiempo. Por lo tanto, debe ser un problema de horario de verano. –

+0

DST me muerde el culo dos veces al año, todos los años. Pensarías que aprendería. – DanSingerman

Respuesta

19

Como willcodejavaforfood ha comentado, esto se debe al horario de verano que finaliza este fin de semana.

Al agregar una duración ActiveSupport tiene algún código para compensar si la hora de inicio es en horario de verano y el tiempo resultante no es (o viceversa).

def since(seconds) 
    f = seconds.since(self) 
    if ActiveSupport::Duration === seconds 
    f 
    else 
    initial_dst = self.dst? ? 1 : 0 
    final_dst = f.dst? ? 1 : 0 
    (seconds.abs >= 86400 && initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f 
    end 
rescue 
    self.to_datetime.since(seconds) 
end 

Si tiene 11:09:27 y agrega un número de días que seguirá recibiendo 11:09:27 en el día que resulte incluso si el horario de verano ha cambiado. Esto da como resultado una hora extra cuando realiza cálculos en segundos.

Un par de ideas:

  • utilizar el método de distance_of_time_in_words ayudante para dar al usuario una indicación de cuánto tiempo queda en su juicio.
  • Calcule la caducidad como Time.now + (14 * 86400) en lugar de usar 14.days.from_now, pero algunos usuarios pueden afirmar que han perdido una hora de prueba.
  • Configure las pruebas para que caduquen a las 23:59:59 del día de caducidad independientemente del tiempo de registro real.
+1

aha, eso es genial, gracias Mike. Sabía que tenía que ser algo así. Intenté establecer el tiempo de expiración usando segundos (ver el final de mi publicación) pero obtuve los mismos resultados. Además, cuando intento distance_of_time_in_words recibo un error: "TypeError: ActiveSupport :: TimeWithZone no puede forzarse en Fixnum". time_ago_in_words funciona bien. –

+0

¿Qué parámetros pasaba a 'distance_of_time_in_words'? 'time_ago_in_words' es solo un contenedor alrededor de' distance_of_time_in_words' con el 2do parámetro establecido en 'Time.now', es decir,' distance_of_time_in_words (from_time, Time.now, include_seconds) ' – mikej

+1

No es un error, es una función. Dependiendo de tu definición de característica. – Kelvin

8

Puede usar la clase Date para calcular la cantidad de días entre hoy y la fecha de caducidad.

expire_date = Date.new(user.trial_expires.year, user.trial_expires.month, user.trial_expires.day) 
days_until_expiration = (expire_date - Date.today).to_i 
+0

Buena idea, gracias Jonas –

+3

'today = Date.new (now.year, now.month, now.day)' se puede simplificar a 'today = Date.today' –

5

Uso since, ejemplo: 14.days.since.to_date

Cuestiones relacionadas