Рубиновый метод с использованием даты рождения, включая месяцы
У меня есть метод в моей пользовательской модели, чтобы вычислить возраст пользователя и вернуть читаемую человеком строку. Мой пользователь может быть в возрасте от 1 месяца и старше, поэтому возвращаемая строка может быть разной в зависимости от того, кому "2 месяца", "1 год" или "2 года и 3 месяца".
Я рассмотрел несколько сообщений SO, чтобы прийти к этому решению. Есть что-то, что я пропускаю Високосные годы? Спасибо!
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
4 ответа
Хотя это может быть лучше опубликовано на сайте 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
драгоценный камень, вы можете воспользоваться 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
Функция позволяет вам рассчитать возраст человека для данной отметки времени. Это также облегчает тестирование функции, если она дает одинаковый результат при одинаковых входных данных.
Вы можете использовать time_ago_in_words:
Class.new.extend(ActionView::Helpers::DateHelper).time_ago_in_words(Time.parse("1981-11-20"))
=> "over 34 years"
Изменить: оно не имеет такой степени детализации, как ваше решение, я знаю. Просто подумал, что это может быть хорошей ссылкой.
Просто еще один вариант, основанный на классе Rational и некоторых вычислениях даты, поддерживаемых Rails.
def age
return 'No Date of Birth' unless date_of_birth.present?
days_alive = Date.now - date_of_birth
years = (days_alive / 365).to_i
months = ((days_alive % 365) / 30).to_i
[pluralized(years, 'year'), pluralized(months, 'month')].compact.join(' ')
end
def pluralized(quantity, noun)
return nil if quantity.zero?
return noun.singularize if quantity == 1
noun.pluralize
end
Использование помощников 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