2009-12-14 26 views
14

Esta pregunta estaba aquí para otros idiomas, así que vamos a ser uno para Ruby.¿Cómo se calcula cuántos años pasaron desde una fecha determinada en Ruby?

¿Cómo calculo la cantidad de años completos que han transcurrido desde una fecha determinada? Como probablemente haya adivinado, eso es para calcular la edad de la persona automáticamente. El más cercano es distance_of_time_in_words rieles ayudante, por lo que la plantilla siguiente

Jack is <%= distance_of_time_in_words (Time.now, Time.local(1950,03,22)) %> old. 

produce

Jack is over 59 years old. 

pero necesito más precisa la función que produce solo número. ¿Hay alguno?

Si existe algún tipo de función auxiliar de Ruby on Rails para esto, esto está bien, aunque la solución pura de Ruby sería mejor.

Editar: la esencia de la pregunta es que se necesita una solución no aproximada. En el 2 nd de marzo, Jack debería tener 59 años y al día siguiente debería tener 60 años. Los años bisiestos y tal deben ser tomados en cuenta.

Respuesta

37

¿Quieres edad que la gente normalmente lo entienden, o está buscando una medida precisa del tiempo transcurrido? Si lo primero, no hay necesidad de preocuparse por los años bisiestos y otras complicaciones. Simplemente necesita calcular una diferencia en años y reducirla si la persona aún no ha cumplido años este año. Si es el último, puede convertir segundos transcurridos en años, como han sugerido otras respuestas.

def age_in_completed_years (bd, d) 
    # Difference in years, less one if you have not had a birthday this year. 
    a = d.year - bd.year 
    a = a - 1 if (
     bd.month > d.month or 
     (bd.month >= d.month and bd.day > d.day) 
    ) 
    a 
end 

birthdate = Date.new(2000, 12, 15) 
today  = Date.new(2009, 12, 14) 

puts age_in_completed_years(birthdate, today) 
+1

Parece que no solo ha respondido la pregunta, sino que también ha formulado la pregunta de una mejor manera :-) –

+1

+1, pero ¿y si hubiera nacido, digamos Date.new (1980, 2, 29)? ;-) –

+1

@Mike Bummer: no hay cumpleaños para ti. Buen punto. Solucionado el código. – FMc

4
require 'date' 

def years_since(dt) 
    delta = (Date.today - Date.parse(dt))/365 
    delta.to_i 
end 
0

¿Qué tal algo como:

def years_diff(from_time,to_time) 
    (((to_time - from_time).abs)/ (365 * 24 * 60 * 60)).to_i 
end 

years_diff(Time.now,Time.local(1950,03,22)) #=> 59 
years_diff(Time.now,Time.local(2009,03,22)) #=> 0 
years_diff(Time.now,Time.local(2008,03,22)) #=> 1 
+1

ActiveSupport 's Esto no va a ir para trabajar cuando la fecha actual está cerca del cumpleaños (años bisiestos!), y para una persona de más de 1460 años de edad va a producir errores cada vez mayores. –

5

que tienen una joya/plugin llamado dotiw que tiene un distance_of_time_in_words_hash que devolverá un hash como: { :years => 59, :months => 11, :days => 27 }. De eso podrías calcular si está cerca de un cierto límite.

1

La misma idea que FM pero con una declaración if simplificada. Obviamente, podría agregar un segundo argumento en lugar de usar la hora actual.

def age(birthdate) 
    now = DateTime.now 
    age = now.year - birthdate.year 
    age -= 1 if(now.yday < birthdate.yday) 
    age 
end 
+1

'yday' es una función genial, gracias. Desafortunadamente, manejará los años bisiestos de manera diferente, si la persona nace más tarde que en febrero. –

+0

de acuerdo con Pavel. 'yday' no es útil para comparar fechas que abarcan años debido a los años bisiestos. –

1

Creo que esto siempre va a funcionar, incluso para alguien con un cumpleaños cerca de un día bisiesto:

require 'date' 

def calculate_age(start_date, end_date) 
    end_date.year - start_date.year - ((end_date.month > start_date.month || (end_date.month == start_date.month && end_date.day >= start_date.day)) ? 0 : 1) 
end 

puts calculate_age(Date.strptime('03/02/1968', '%m/%d/%Y'), Date.strptime('03/02/2010', '%m/%d/%Y')) 

La edad calculada con este método en el ejemplo de la llamada anterior es 42, que es correcto a pesar 1968 es un año bisiesto y el cumpleaños está cerca de un día bisiesto.

Además, de esta manera no hay necesidad de crear una variable local.

4

Un enfoque que se ocupa de los años bisiestos

Cada vez que usted está calculando años transcurridos desde una fecha, usted tiene que decidir cómo manejar salto año. Aquí está mi enfoque, que creo que es muy legible, y es capaz de tomarse años largos sin utilizar ninguna lógica de "caso especial".

def years_completed_since(start_date, end_date) 

    if end_date < start_date 
    raise ArgumentError.new(
     "End date supplied (#{end_date}) is before start date (#{start_date})" 
    ) 
    end 

    years_completed = end_date.year - start_date.year 

    unless reached_anniversary_in_year_of(start_date, end_date) 
    years_completed -= 1 
    end 

    years_completed 
end 

# No special logic required for leap day; its anniversary in a non-leap 
# year is considered to have been reached on March 1. 
def reached_anniversary_in_year_of(original_date, new_date) 
    if new_date.month == original_date.month 
    new_date.day >= original_date.day 
    else 
    new_date.month > original_date.month 
    end 
end 
0

¿Qué tal esto:

def age_in_years(date) 
    # Difference in years, less one if you have not had a birthday this year. 
    today = Date.today 
    age = today.year - date.year 
    age = age - 1 if [date.day, date.month, today.year].join('/').to_date > Date.today 
end 
2

puede utilizar la gema de rubíes adroit-age

Funciona para los años bisiestos también ..

age = AdroitAge.find_age("23/01/1990") 

actualización

require 'adroit-age' 

dob = Date.new(1990,1,23) 
or 
dob = "23/01/1990".to_date 

age = dob.find_age 
#=> 23 
0

d2.year - d1.year - (d2.month > d1.month || (d2.month == d1.month && d2.day >= d1.day) ? 0 : 1)

+0

¡Bienvenido a SO! Intenta dar alguna explicación con tus respuestas. – codeMagic

1

me ocurrió lo siguiente, basado en un razonamiento similar como @FMc En primer lugar, calcular el diff entre el año actual y el año del cumpleaños. A continuación, se resumen a cumpleaños y comprobar la fecha resultante: si es mayor que el actual, disminuir diff 1. para ser utilizado en aplicaciones Rails ya que se basa en el método de years

def age(birthday, today) 
    diff = today.year - birthday.year 
    (birthday + diff.years > today) ? (diff - 1) : diff 
end 
Cuestiones relacionadas