web-dev-qa-db-fra.com

Obtenir l'âge de la personne en rubis

Je voudrais avoir l'âge d'une personne 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

Existe-t-il une manière plus rubyish de calculer l'âge?

117
Mantas

Je sais que je suis en retard à la fête ici, mais la réponse acceptée va casser horriblement lorsque nous essayons de calculer l'âge de quelqu'un né le 29 février 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
398
philnash

J'ai trouvé cette solution efficace et 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 manipuler année bissextile et autres.

48
PJ.

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
34
Sadegh

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

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

Logic from here - Calculer 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.

16
Vikrant Chaudhary
(Date.today.strftime('%Y%m%d').to_i - dob.strftime('%Y%m%d').to_i) / 10000
9
pguardiario

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 Time renvoie des secondes

6
jlebrijo

Les réponses à ce jour sont 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. Cette solution est préférable 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 Time associée) depuis l'événement. Ensuite, 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 manière, tant que vous conservez la valeur de la date de naissance originale, il n’est pas tenu compte des années bissextiles.

6
Bob Aman

J'aime celui la: 

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

Cette réponse est la meilleure, faites-la passer à la place.


J'aime la solution de @ philnash, mais le conditionnel pourrait être compact. Ce que cette expression booléenne fait est de comparer les paires [mois, jour] en utilisant ordre lexicographique , afin que l'on puisse simplement utiliser la comparaison de chaînes de Ruby à la place:

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

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 prend tout son sens lorsque vous réalisez ce que ça 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
2
br3nt

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

Ajoutez dotiw au Gemfile:

gem 'dotiw'

Sur la ligne de commande:

bundle

Incluez le 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
1
mindriot

Je pense que cela est fonctionnellement équivalent à la réponse de @ philnash, mais que l’OMI est plus compréhensible.

class BirthDate
  def initialize(birth_date)
    @birth_date = birth_date
    @now = Time.now.utc.to_date
  end

  def time_ago_in_years
    if today_is_before_birthday_in_same_year?
      age_based_on_years - 1
    else
      age_based_on_years
    end
  end

  private

  def age_based_on_years
    @now.year - @birth_date.year
  end

  def today_is_before_birthday_in_same_year?
    (@now.month < @birth_date.month) || ((@now.month == @birth_date.month) && (@now.day < @birth_date.day))
  end
end

Usage:

> BirthDate.new(Date.parse('1988-02-29')).time_ago_in_years
 => 31 
1
Jason Swett

DateHelper peut être utilisé pour obtenir des années seulement

puts time_ago_in_words '1999-08-22'

presque 20 ans

0
7uthaifah

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

En supposant que nous utilisons Rails, nous appelons la méthode age sur un modèle et que le modèle possède une colonne de base de données de date dob. Ceci diffère des autres réponses car cette méthode utilise des chaînes pour déterminer si nous sommes avant l'anniversaire de cette année.

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

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

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îne au début était le résultat.

Vous pouvez aussi faire ça

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 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

????????

0
Cruz Nunez

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
0
Oleksiy Nosov

Entré avec une variation 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
0
derosm2

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

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

Ce qui suit semble fonctionner (mais j'apprécierais que cela soit vérifié).

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