在Ruby中获取人的年龄

我想从生日那天就得到一个人的年龄。 now - birthday / 365不工作,因为有些年份有366天。 我想出了以下代码:

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

有更多的Ruby'ish方式来计算年龄?

我知道我在这里参加晚会的时间已经很晚了,但是在试图计算一个闰年出生在二月二十九日的人的年龄的时候,接受的答案将会大打折扣。 这是因为对birthday.to_date.change(:year => now.year)的调用会创build一个无效的date。

我使用了下面的代码(在Rails项目中):

 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 

我发现这个解决scheme能够很好地工作,对其他人可读:

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

容易,你不必担心处理闰年等。

用这个:

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

Ruby on Rails中的一个class轮(ActiveSupport)。 处理闰年,闰秒等。

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

从这里开始的逻辑 – 用C#计算年龄

假设两个date都在同一时区,如果两者都不在to_s()之前调用utc()

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

迄今为止的答案有点奇怪。 你最初的尝试是非常接近正确的方式来做到这一点:

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

您将得到一个小数结果,所以随意将结果转换为与to_i的整数。 这是一个更好的解决scheme,因为它将date差别正确地视为以天为单位的时间段(或者在相关时间类的情况下的秒数)。 然后按照一年中的天数来简单的划分你的年龄。 以这种方式计算年龄时,只要保留原来的DOB值,闰年就不需要补贴。

我喜欢这一个:

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

我的build议:

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

诀窍是,时间的减号操作返回秒

这个答案是最好的,反而upvote。


我喜欢@ philnash的解决scheme,但条件可能是compacter。 布尔expression式所做的是使用字典顺序来比较[month,day]对,所以可以使用ruby的string比较来代替:

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

这是这个答案的转换(它收到了很多票):

 # 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 

它的方法绝对是独一无二的,但是当你意识到它的作用时,它是非常有意义的:

 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 

由于Ruby on Rails被标记,所以dotiw gem覆盖了Rails内置的distance_of_times_in_words,并提供了可用于确定年龄的distance_of_times_in_words_hash 。 闰年多年来处理得很好,但要注意,如果需要这个详细程度的话,2月29日对于需要理解的日子部分有影响。 此外,如果您不喜欢dotiw如何更改distance_of_time_in_words的格式,请使用:模糊选项恢复为原始格式。

添加dotiw到Gemfile:

 gem 'dotiw' 

在命令行上:

 bundle 

将DateHelper包含在适当的模型中以获得对distance_of_time_in_words和distance_of_time_in_words_hash的访问权限。 在这个例子中,模型是“用户”,生日字段是“生日”。

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

将此方法添加到相同的模型。

 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 

用法:

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

以下似乎工作(但我会很感激,如果它被检查)。

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

如果你不关心一两天,这将是更短,相当自我解释。

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

好的,这个怎么样:

 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 

这是假设我们正在使用rails,在模型上调用age方法,并且该模型具有date数据库列dob 。 这与其他答案不同,因为此方法使用string来确定我们是否在今年的生日之前。

例如,如果dob是2004/2/28,而today是2014/2/28,那么age将是2014 - 200410 。 花车将是02280229b4bday将为"0228" < "0229"true 。 最后,我们将从age1 ,得到9

这将是两次比较的正常方式。

 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 

这工作是一样的,但是b4bday线太长了。 2016年也是不必要的。 开始的string比较是结果。

你也可以做到这一点

 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 

如果你不使用rails,试试这个

 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 

👍🏼

我觉得不要数数月,因为你可以通过使用Time.zone.now.yday得到一年中的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 
  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) 

考虑闰年(并假设有效的支持):

 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将正确修改date以考虑非闰年(当生日是02-29 )。

我也必须处理这个,但几个月。 变得太复杂了。 我能想到的最简单的方法是:

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

你可以在12个月内做同样的事情:

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

这将使用Date类来增加月份,这将处理28天和闰年等。