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?
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
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.
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 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.
(Date.today.strftime('%Y%m%d').to_i - dob.strftime('%Y%m%d').to_i) / 10000
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
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.
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, 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
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
É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
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
DateHelper peut être utilisé pour obtenir des années seulement
puts time_ago_in_words '1999-08-22'
presque 20 ans
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
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 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
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
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]