在 Ruby 中获取人的年龄

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

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


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

还有比这更鲁比式的计算年龄的方法吗?

69201 次浏览

用这个:

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

我发现这个解决方案可以很好地工作,并且对其他人来说是可读的:

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

很简单,你不需要担心处理闰年之类的事情。

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

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

您将得到一个小数结果,因此可以随意地将结果转换为 to_i的整数。这是一个更好的解决方案,因为它正确地将日期差异视为事件发生后以天(或相关 Time 类的情况下以秒为单位)计算的时间段。然后用一年中的天数除以年龄。用这种方法计算年龄时,只要保留原始出生日期,闰年就不需要考虑。

下面的方法似乎可行(但如果检查一下我会很感激)。

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

我知道我来晚了,但是当我试图推算出一个出生在闰年2月29日的人的年龄时,这个公认的答案将会被打破。这是因为对 birthday.to_date.change(:year => now.year)的调用创建了一个无效的日期。

我使用了以下代码:

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

Ruby on Rails (ActiveSupport)中的一行程序。处理闰年、闰秒等等。

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

逻辑从这里-我如何计算某人的年龄基于一个日期时间类型的生日?

假设两个日期在同一时区,如果不在两个时区的 to_fs()之前调用 utc()

我喜欢这个:

now = Date.current
age = now.year - dob.year
age -= 1 if now.yday < dob.yday
(Date.today.strftime('%Y%m%d').to_i - dob.strftime('%Y%m%d').to_i) / 10000

我也不得不面对这些,但是几个月了。变得太复杂了。我能想到的最简单的方法是:

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

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

这个回答 是最好的,改为支持它。


我喜欢@philnash 的解决方案,但条件可以更简洁。这个布尔表达式的作用是使用 字典编纂顺序字典编纂顺序比较[ month,day ]对,所以可以使用 ruby 的字符串比较:

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

考虑闰年(并假设积极支持存在) :

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

我的建议是:

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

诀窍在于,使用 Time 的减号操作将返回秒

因为 Ruby on Rails 被标记了,所以 Dotiw gem 覆盖了 Rails 内置的 用言语表达的距离,并提供了 单词散列,可以用来确定年龄。闰年对于年份部分处理得很好,尽管要知道2月29日对于日子部分确实有影响,如果需要这种细节水平,那么就需要理解它。另外,如果您不喜欢 dotiw 如何更改 range _ of _ time _ in _ words 的格式,可以使用: ague 选项恢复到原来的格式。

将 dotiw 添加到 Gemfile:

gem 'dotiw'

在命令行上:

bundle

将 DateHelper 包含在适当的模型中,以获得对 range _ of _ time _ in _ words 和 far _ of _ time _ in _ words _ hash 的访问。在这个例子中,模型是“ User”,生日字段是“ life”。

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

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

# 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

如果你不关心一两天,这将是短期和相当不言自明。

(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

这是假设我们正在使用 Rail,调用模型上的 age方法,并且模型有一个日期数据库列 dob。这与其他答案不同,因为这个方法使用字符串来确定我们是否在今年的生日之前。

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

这是比较两次的正常方法。

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

如果你不使用轨道,试试这个

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可以得到一年中的确切日期。

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 age on = Date.today
(_ = on.year - birthday.year) - (on < birthday.since(_.years) ? 1 : 0)
end

提出了这个 解决方案的 Rails 变体

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

我相信这在功能上等同于@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

DateHelper 只能用于获取年

puts time_ago_in_words '1999-08-22'

快20年了

  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```
class User
def age
return unless birthdate
(Time.zone.now - birthdate.to_time) / 1.year
end
end

可通过以下测试进行检查:

RSpec.describe User do
describe "#age" do
context "when born 29 years ago" do
let!(:user) { create(:user, birthdate: 29.years.ago) }


it "has an age of 29" do
expect(user.age.round).to eq(29)
end
end
end
end