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
因为 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
# 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
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
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