135 votes

Obtenir l'âge de la personne en Ruby

J'aimerais obtenir l'âge d'une personne à partir de sa date d'anniversaire. now - birthday / 365 ne fonctionne pas, car certaines années comptent 366 jours. J'ai trouvé le code suivant :

now = Date.today
year = now.year - birth_date.year

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

Existe-t-il une méthode plus proche de Ruby pour calculer l'âge ?

7 votes

J'aime cette question parce qu'elle met en évidence l'idée qu'il y a des façons de faire " plus Ruby " et " moins Ruby ". Il est important non seulement d'être logiquement correct (ce que vous pourriez être en copiant la réponse C#), mais aussi stylistiquement correct. Et la réponse d'Adinochestva utilise bien l'idiome Ruby.

428voto

philnash Points 8783

Je sais que je suis en retard sur le sujet, mais la réponse acceptée est très mauvaise lorsqu'on essaie de déterminer l'âge d'une personne née le 29 février d'une année bissextile. En effet, l'appel à birthday.to_date.change(:year => now.year) crée une date invalide.

J'ai utilisé le code suivant à la place :

require 'date'

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

4 votes

Utilisez celui-ci, pas celui qui est coché et qui ne gère pas les années bissextiles.

0 votes

Pourquoi renvoyer 0 || 1 au lieu de true || false ?

2 votes

@alex0112 Parce que le résultat (0 ou 1) de ce conditionnel, certes déroutant, est soustrait de la différence d'années entre aujourd'hui et la date de naissance. Le but est de savoir si la personne a déjà eu son anniversaire cette année et si ce n'est pas le cas, elle a 1 an de moins que la différence entre les années.

53voto

PJ. Points 997

J'ai trouvé cette solution qui fonctionne bien et qui est lisible pour d'autres personnes :

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

C'est facile et vous n'avez pas à vous préoccuper de la gestion des années bissextiles et autres.

3 votes

Cela nécessite Rails (pour age.years), mais il est possible de faire en sorte que Rails ne soit pas nécessaire si vous faites quelque chose comme Date.today.month < birthday.month or Date.today.month == birthday.month && Date.today.mday < birthday.mday .

0 votes

Vous avez raison - désolé, j'ai supposé que c'était Rails, car la question en était assortie. Mais oui, facilement modifiable pour Ruby uniquement.

1 votes

J'avais d'abord choisi celui-ci parce qu'il est le plus beau, mais en production, il est souvent erroné, pour des raisons qui m'échappent. La version ci-dessus, qui utilise Time.now.utc.to_date, semble mieux fonctionner.

33voto

Adinochestva Points 4459

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

41 votes

Cela ne fonctionne pas si birthday.to_date est une année bissextile et que l'année en cours ne l'est pas. Ce n'est pas très fréquent, mais cela m'a posé des problèmes.

1 votes

Downvoting pour encourager la réponse de philnash.

2 votes

Une autre raison de préférer Réponse de philnash est qu'il fonctionne avec Ruby, alors que la réponse acceptée ne fonctionne qu'avec rails/activesupport .

17voto

Vikrant Chaudhary Points 4306

One liner en Ruby on Rails (ActiveSupport). Gère les années bissextiles, les secondes bissextiles et tout le reste.

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

Logique à partir d'ici - Comment calculer l'âge d'une personne à partir d'une date d'anniversaire de type DateTime ?

En supposant que les deux dates se situent dans le même fuseau horaire, si ce n'est pas le cas, appeler <code>utc()</code> avant <code>to_fs()</code> sur les deux.

1 votes

(Date.today.to_s(:number).to_i - birthday.to_date.to_s(:number).to_i)/1e4.to_i fonctionne également

0 votes

FWIW, mais alors ma garantie sur les "secondes intercalaires" sera invalidée ;-) (FWIW part 2, Ruby ne supporte pas les "leap seconds" de toute façon) :-)

1 votes

Je ne sais pas pourquoi je reçois des commentaires négatifs à ce sujet. Pouvez-vous m'expliquer, chers downvoters ?

7voto

Bob Aman Points 19110

Les réponses sont pour l'instant assez bizarres. Votre première tentative é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 . Cette solution est meilleure car elle traite correctement la différence de date comme une période de temps mesurée en jours (ou en secondes dans le cas de la classe Time associée) depuis l'événement. Une simple division par le nombre de jours d'une année permet alors d'obtenir l'âge. Lorsque l'on calcule l'âge en années de cette manière, tant que l'on conserve la valeur originale de la date de naissance, il n'est pas nécessaire de tenir compte des années bissextiles.

0 votes

Birthday = Time.mktime(1960,5,5) me donne un résultat hors plage (problème d'époque ?)

0 votes

Oui, les questions d'époque. J'ai mis à jour la réponse pour résoudre ce problème.

0 votes

birthday = DateTime.now - 1.year me donne un âge de 0. Malheureusement, diviser par 365,25 est un peu imprécis.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X