在Ruby中获取人的年龄

时间:2009-05-04 08:27:13

标签: ruby-on-rails ruby

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

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

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

有更多Ruby的计​​算年龄的方法吗?

24 个答案:

答案 0 :(得分:400)

我知道我在这里参加派对已经很晚了,但是当我试图计算出闰年2月29日出生的人的年龄时,接受的答案会非常糟糕。这是因为对birthday.to_date.change(:year => now.year)的调用会创建无效日期。

我使用了以下代码(在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

答案 1 :(得分:49)

我发现这个解决方案运行良好,并且可供其他人阅读:

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

简单,您无需担心处理闰年等问题。

答案 2 :(得分:33)

使用此:

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

答案 3 :(得分:16)

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

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

此处的逻辑 - Calculate age in C#

假设两个日期都在同一时区,如果没有在utc()之前调用to_s()

答案 4 :(得分:9)

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

答案 5 :(得分:6)

到目前为止,答案有点奇怪。您最初的尝试非常接近正确的方法:

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

您将获得小数结果,因此可以随意将结果转换为to_i的整数。这是一个更好的解决方案,因为它正确地将日期差异视为自事件以来以天(或相关时间类的情况下为秒)测量的时间段。然后根据一年中的天数进行简单划分即可得出年龄。以这种方式计算年龄时,只要保留原始DOB值,就不需要考虑闰年。

答案 6 :(得分:6)

我的建议:

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

技巧是使用Time的减号操作返回秒

答案 7 :(得分:4)

我喜欢这个:

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

答案 8 :(得分:4)

This answer是最好的,而不是投票。


我喜欢@ philnash的解决方案,但有条件的可能更紧凑。布尔表达式的作用是使用lexicographic order比较[月,日]对,因此可以使用ruby的字符串比较:

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

答案 9 :(得分:2)

这是this answer的转换(获得了很多选票):

# 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

答案 10 :(得分:1)

我相信这在功能上等同于@philnash的答案,但IMO更容易理解。

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

用法:

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

答案 11 :(得分:1)

由于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的格式,请使用:vague选项恢复为原始格式。

将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

答案 12 :(得分:0)

  def computed_age
    if birth_date.present?
      current_time.year - birth_date.year - (age_by_bday || check_if_newborn ? 0 : 1)
    else
      age.presence || 0
    end
  end


  private

  def current_time
    Time.now.utc.to_date
  end

  def age_by_bday
    current_time.month > birth_date.month
  end

  def check_if_newborn
    (current_time.month == birth_date.month && current_time.day >= birth_date.day)
  end```

答案 13 :(得分:0)

了解此solution

的Rails变体
def age(dob)
    now = Date.today
    age = now.year - dob.year
    age -= 1 if dob > now.years_ago(age)
    age
end

答案 14 :(得分:0)

我认为不计数月数会更好,因为您可以使用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

答案 15 :(得分:0)

DateHelper仅可用于获取年份

puts time_ago_in_words '1999-08-22'
  

近20年

答案 16 :(得分:0)

好的,这个:

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方法,并且模型具有日期数据库列dob。这与其他答案不同,因为此方法使用字符串来确定我们是否在今年的生日之前。

例如,如果dob为2004/2/28且today为2014/2/28,则age将为2014 - 200410。浮点数为02280229b4bday将为"0228" < "0229"true。最后,我们将从1中减去age并获取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年也是不必要的。开头的字符串比较是结果。

你也可以这样做

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

答案 17 :(得分:0)

如果你不关心一两天,这会更短,而且非常自我解释。

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

答案 18 :(得分:0)

以下似乎有效(但如果检查过,我会很感激)。

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

答案 19 :(得分:-1)

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

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会正确修改日期以考虑非闰年(生日为02-29时)。

答案 20 :(得分:-1)

这是我的解决方案,它还允许计算特定日期的年龄:

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

答案 21 :(得分:-1)

Time.now.year - self.birthdate.year - (birthdate.to_date.change(:year => Time.now.year) > Time.now.to_date ? 1 : 0)

答案 22 :(得分:-1)

  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

答案 23 :(得分:-2)

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

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天和闰年等。