Obtenir l’âge de la personne en Ruby

J’aimerais avoir l’âge d’une personne à partir de son anniversaire. now - birthday / 365 ne fonctionne pas, car certaines années ont 366 jours. Je suis venu avec le code suivant:

 now = Date.today year = now.year - birth_date.year if (date+year.year) > now year = year - 1 end 

Y a-t-il une manière plus Ruby’ish de calculer l’âge?

Je sais que je suis en retard à la fête ici, mais la réponse acceptée se brisera horriblement en essayant de déterminer l’âge d’une personne née le 29 février au cours d’une année bissextile. En effet, l’appel à birthday.to_date.change(:year => now.year) crée une date non valide.

J’ai utilisé le code suivant (dans un projet Rails) à la place:

 def age(dob) now = Time.now.utc.to_date now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1) end 

J’ai trouvé cette solution pour bien fonctionner et être lisible par d’autres personnes:

  age = Date.today.year - birthday.year age -= 1 if Date.today < birthday + age.years #for days before birthday 

Facile et vous n'avez pas à vous soucier de la gestion des années bissextiles et autres.

Utilisez ceci:

 def age now = Time.now.utc.to_date now.year - birthday.year - (birthday.to_date.change(:year => now.year) > now ? 1 : 0) end 

Une doublure en Ruby on Rails (ActiveSupport). Gère les années bissextiles, les secondes bissextiles et tout.

 def age(birthday) (Time.now.to_s(:number).to_i - birthday.to_time.to_s(:number).to_i)/10e9.to_i end 

Logique d’ici – Calculez l’âge en C #

En supposant que les deux dates sont dans le même fuseau horaire, sinon, appelez utc() avant to_s() sur les deux.

 (Date.today.strftime('%Y%m%d').to_i - dob.strftime('%Y%m%d').to_i) / 10000 

Les réponses sont jusqu’ici un peu bizarres. Votre tentative initiale était assez proche de la bonne façon de procéder:

 birthday = DateTime.new(1900, 1, 1) age = (DateTime.now - birthday) / 365.25 # or (1.year / 1.day) 

Vous obtiendrez un résultat fractionnaire, alors n’hésitez pas à convertir le résultat en un entier avec to_i . C’est une meilleure solution car elle traite correctement la différence de date comme une période mesurée en jours (ou en secondes dans le cas de la classe temporelle associée) depuis l’événement. Une simple division par le nombre de jours dans une année vous donne l’âge. Lorsque vous calculez l’âge en années de cette façon, tant que vous conservez la valeur de la DOB d’origine, vous ne devez pas prendre en compte les années bissextiles.

Ma suggestion:

 def age(birthday) ((Time.now - birthday.to_time)/(60*60*24*365)).floor end 

L’astuce est que l’opération moins avec le temps retourne des secondes

J’aime celui la:

 now = Date.current age = now.year - dob.year age -= 1 if now.yday < dob.yday 

Cette réponse est la meilleure, à la place.


J’aime la solution de @ philnash, mais le conditionnel pourrait être compacter. Ce que fait cette expression booléenne est de comparer les paires [mois, jour] en utilisant l’ ordre lexicographique .

 def age(dob) now = Date.today now.year - dob.year - (now.strftime('%m%d') < dob.strftime('%m%d') ? 1 : 0) end 

Ceci est une conversion de cette réponse (il a reçu beaucoup de votes):

 # convert dates to yyyymmdd format today = (Date.current.year * 100 + Date.current.month) * 100 + Date.today.day dob = (dob.year * 100 + dob.month) * 100 + dob.day # NOTE: could also use `.strftime('%Y%m%d').to_i` # convert to age in years years_old = (today - dob) / 10000 

C’est vraiment unique dans son approche, mais cela se comprend parfaitement lorsque vous réalisez ce que cela fait:

 today = 20140702 # 2 July 2014 # person born this time last year is a 1 year old years = (today - 20130702) / 10000 # person born a year ago tomorrow is still only 0 years old years = (today - 20130703) / 10000 # person born today is 0 years = (today - 20140702) / 10000 # person born today is 0 years old # person born in a leap year (eg. 1984) comparing with non-leap year years = (20140228 - 19840229) / 10000 # 29 - a full year hasn't yet elapsed even though some leap year babies think it has, technically this is the last day of the previous year years = (20140301 - 19840229) / 10000 # 30 # person born in a leap year (eg. 1984) comparing with leap year (eg. 2016) years = (20160229 - 19840229) / 10000 # 32 

Étant donné que Ruby on Rails est marqué, le gem dotiw remplace le paramètre intégré distance_of_times_in_words de Rails et fournit la distance_of_times_in_words_hash qui peut être utilisée pour déterminer l’âge. Les années bissextiles sont traitées correctement pour la partie des années, mais sachez que le 29 février a un effet sur la partie des jours qui nécessite une compréhension de la nécessité de ce niveau de détail. De plus, si vous n’aimez pas comment dotiw change le format de distance_of_time_in_words, utilisez l’option: vague pour revenir au format d’origine.

Ajouter dotiw au Gemfile:

 gem 'dotiw' 

Sur la ligne de commande:

 bundle 

Incluez le composant DateHelper dans le modèle approprié pour accéder à distance_of_time_in_words et distance_of_time_in_words_hash. Dans cet exemple, le modèle est «Utilisateur» et le champ anniversaire est «anniversaire».

 class User < ActiveRecord::Base include ActionView::Helpers::DateHelper 

Ajoutez cette méthode à ce même modèle.

 def age return nil if self.birthday.nil? date_today = Date.today age = distance_of_time_in_words_hash(date_today, self.birthday).fetch("years", 0) age *= -1 if self.birthday > date_today return age end 

Usage:

 u = User.new("birthday(1i)" => "2011", "birthday(2i)" => "10", "birthday(3i)" => "23") u.age 

Ce qui suit semble fonctionner (mais je l’apprécierais si c’était vérifié).

 age = now.year - bday.year age -= 1 if now.to_a[7] < bday.to_a[7] 

Si vous ne vous souciez pas d’un jour ou deux, cela serait plus court et assez explicite.

 (Time.now - Time.gm(1986, 1, 27).to_i).year - 1970 

Ok, qu’en est-il de ceci:

 def age return unless dob t = Date.today age = t.year - dob.year b4bday = t.strftime('%m%d') < dob.strftime('%m%d') age - (b4bday ? 1 : 0) end 

Cela suppose que nous utilisons des rails, en appelant la méthode age sur un modèle, et que le modèle dispose d'une colonne de firebase database date. Ceci est différent des autres réponses car cette méthode utilise des chaînes pour déterminer si nous sums avant l'anniversaire de cette année.

Par exemple, si dob est 2004/2/28 et today est 2014/2/28, l' age sera 2014 - 2004 ou 10 . Les flotteurs seront 0228 et 0229 . b4bday sera "0228" < "0229" ou true . Enfin, nous allons soustraire 1 à l' age et obtenir 9 .

Ce serait la manière normale de comparer les deux temps.

 def age return unless dob t = Date.today age = today.year - dob.year b4bday = Date.new(2016, t.month, t.day) < Date.new(2016, dob.month, dob.day) age - (b4bday ? 1 : 0) end 

Cela fonctionne de la même manière, mais la ligne b4bday est trop longue. L'année 2016 est également inutile. La comparaison de chaînes au début était le résultat.

Vous pouvez aussi le faire

 Date::DATE_FORMATS[:md] = '%m%d' def age return unless dob t = Date.today age = t.year - dob.year b4bday = t.to_s(:md) < dob.to_s(:md) age - (b4bday ? 1 : 0) end 

Si vous n'utilisez pas de rails, essayez ceci

 def age(dob) t = Time.now age = t.year - dob.year b4bday = t.strftime('%m%d') < dob.strftime('%m%d') age - (b4bday ? 1 : 0) end 

👍🏼

Je pense qu’il est préférable de ne pas compter les mois, car vous pouvez obtenir le jour exact de l’année en utilisant Time.zone.now.yday .

 def age years = Time.zone.now.year - birthday.year y_days = Time.zone.now.yday - birthday.yday y_days < 0 ? years - 1 : years end 

Entré avec une variante Rails de cette solution

 def age(dob) now = Date.today age = now.year - dob.year age -= 1 if dob > now.years_ago(age) age end 
  def birthday(user) today = Date.today new = user.birthday.to_date.change(:year => today.year) user = user.birthday if Date.civil_to_jd(today.year, today.month, today.day) >= Date.civil_to_jd(new.year, new.month, new.day) age = today.year - user.year else age = (today.year - user.year) -1 end age end 
 Time.now.year - self.birthdate.year - (birthdate.to_date.change(:year => Time.now.year) > Time.now.to_date ? 1 : 0) 

Pour prendre en compte les années bissextiles (et en supposant une présence de soutien actif):

 def age return unless birthday now = Time.now.utc.to_date years = now.year - birthday.year years - (birthday.years_since(years) > now ? 1 : 0) end 

years_since modifiera correctement la date pour tenir compte des années non bissextiles (lorsque l’anniversaire est 02-29 ).

Voici ma solution qui permet également de calculer l’âge à une date précise:

 def age on = Date.today (_ = on.year - birthday.year) - (on < birthday.since(_.years) ? 1 : 0) end 

J’ai dû faire face à cela aussi, mais pendant des mois. Devenu trop compliqué. La façon la plus simple de penser à cela était:

 def month_number(today = Date.today) n = 0 while (dob >> n+1) <= today n += 1 end n end 

Vous pourriez faire la même chose avec 12 mois:

 def age(today = Date.today) n = 0 while (dob >> n+12) <= today n += 1 end n end 

Cela utilisera la classe Date pour incrémenter le mois, qui traitera 28 jours et l'année bissextile, etc.