I have a method on my user model to calculate the user's age and return a human readable string. My user's can be between 1 month old and above so the returned string is different depending on if the person is "2 months old" or "1 year old" or "2 years and 3 months old".
I have reviewed few SO posts to come to this solution. Is there anything I am missing? Leap years? Thank you!
def age
dob = self.date_of_birth
# if a date of birth is not nil
if dob != nil
# get current date
now = Date.current
# has person had their birthday yet this year
had_birthday = ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? true : false)
# if yes then subtract this year from birthday year, if not then also subtract 1 to get how many full years old they are
years = now.year - dob.year - (had_birthday ? 0 : 1)
# get the calendar month difference from birthdya calendar month and today's calendar month. if they have not had their birthdya yet then subtract the difference from 12
months = had_birthday ? now.month - dob.month : 12 - (now.month - dob.month)
# for under 1 year olds
if years == 0
return months > 1 ? months.to_s + " months old" : months.to_s + " month old"
# for 1 year olds
elsif years == 1
return months > 1 ? years.to_s + " year and " + months.to_s + " months old" : years.to_s + " year and " + months.to_s + " month old"
# for older than 1
else
return months > 1 ? years.to_s + " years and " + months.to_s + " months old" : years.to_s + " years and " + months.to_s + " month old"
end
# No date of birth saved so can not calculate age
else
return "No Date of Birth"
end
end
答案 0 :(得分:5)
虽然这可能会更好地发布到codereview网站,但我仍然会给你我的想法。
你已经写了一个相当长的方法,可能是一些较小的方法。
首先,我会写一个方法,花费一个月的年数,并将其分成自己的函数。
def readable_age(years, months)
# for under 1 year olds
if years == 0
return months > 1 ? months.to_s + " months old" : months.to_s + " month old"
# for 1 year olds
elsif years == 1
return months > 1 ? years.to_s + " year and " + months.to_s + " months old" : years.to_s + " year and " + months.to_s + " month old"
# for older than 1
else
return months > 1 ? years.to_s + " years and " + months.to_s + " months old" : years.to_s + " years and " + months.to_s + " month old"
end
end
但是,如果你不介意在你的项目中添加一些依赖项,你可以利用actionview
gem,你可以利用pluralize
函数。
def readable_age(years, months)
year_text = ''
if years == 0
year_text = "#{years} #{pluralize('year', years)} and "
end
"#{year_text}#{pluralize('month', months)} old"
end
现在您的功能可以计算年数和月数。
def age(t)
dob = self.date_of_birth
months = (t.year * 12 + t.month) - (dob.year * 12 + dob.month)
# months / 12 will give the number of years
# months % 12 will give the number of months
readable_age(months / 12, 15 % 12)
end
修改强>
我将日期对象传递到age
函数的原因是允许您计算给定时间戳的人的年龄。如果在给定相同输入的情况下产生相同的结果,它还可以更容易地测试函数。
答案 1 :(得分:4)
您可以使用time_ago_in_words:
Class.new.extend(ActionView::Helpers::DateHelper).time_ago_in_words(Time.parse("1981-11-20"))
=> "over 34 years"
编辑:我知道,它与您的解决方案没有相同的粒度。只是觉得它可能是一个很好的参考。
答案 2 :(得分:1)
基于Rational类的另一个选项和Rails支持的一些日期计算。
% python3
Python 3.4.3 (default, Mar 26 2015, 22:03:40)
[GCC 4.9.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> class A:
... def f(self):
... nonlocal __x
...
[4] 19173 segmentation fault (core dumped) python3
答案 3 :(得分:0)
使用Rails助手:
DateHelper = Class.new.extend(ActionView::Helpers::DateHelper)
DateHelper.time_ago_in_words(Time.parse("2002-02-20"))
=> "almost 15 years"
http://api.rubyonrails.org/classes/ActionView/Helpers/DateHelper.html#method-i-time_ago_in_words