Как рассчитать, сколько лет прошло с той или иной даты в Ruby?
Этот вопрос был здесь для других языков, поэтому пусть здесь будет один для Ruby.
Как рассчитать количество полных лет, прошедших с данной даты? Как вы, наверное, догадались, что автоматически рассчитывать возраст человека. Ближайшим является distance_of_time_in_words
помощник Rails, поэтому следующий шаблон
Jack is <%= distance_of_time_in_words (Time.now, Time.local(1950,03,22)) %> old.
дает
Jack is over 59 years old.
Но мне нужна более точная функция, которая дает просто число. Есть один?
Если для этого существует какая-то вспомогательная функция Ruby on Rails, это нормально, хотя чистое решение Ruby будет лучше.
Изменить: суть вопроса в том, что требуется неприблизительное решение. На 2 nd марта Джек должен быть 59 лет, а на следующий день ему должно быть 60 лет. Високосные годы и тому подобное должны быть приняты во внимание.
Ответы
Ответ 1
Вы хотите возраст, как обычно это понимают люди, или вы ищете точную меру времени? Если первое, нет необходимости беспокоиться о високосных годах и других осложнениях. Вам просто нужно вычислить разницу в годах и уменьшить ее, если в этом году у человека еще нет дня рождения. Если последний, вы можете конвертировать секунды, прошедшие через годы, как и другие ответы.
def age_in_completed_years (bd, d)
# Difference in years, less one if you have not had a birthday this year.
a = d.year - bd.year
a = a - 1 if (
bd.month > d.month or
(bd.month >= d.month and bd.day > d.day)
)
a
end
birthdate = Date.new(2000, 12, 15)
today = Date.new(2009, 12, 14)
puts age_in_completed_years(birthdate, today)
Ответ 2
У меня есть gem/plugin под названием dotiw, у которого есть distance_of_time_in_words_hash
, который вернет хэш вроде: { :years => 59, :months => 11, :days => 27 }
. Из этого вы могли бы выработать, если он приближается к определенному пределу.
Ответ 3
require 'date'
def years_since(dt)
delta = (Date.today - Date.parse(dt)) / 365
delta.to_i
end
Ответ 4
Подход, который обрабатывает високосные годы
Всякий раз, когда вы вычисляете прошедшие годы с даты, вы должны решить, как обрабатывать високосный год. Вот мой подход, который, по моему мнению, очень читабельен и способен преодолевать високосные годы без использования какой-либо логики "особого случая".
def years_completed_since(start_date, end_date)
if end_date < start_date
raise ArgumentError.new(
"End date supplied (#{end_date}) is before start date (#{start_date})"
)
end
years_completed = end_date.year - start_date.year
unless reached_anniversary_in_year_of(start_date, end_date)
years_completed -= 1
end
years_completed
end
# No special logic required for leap day; its anniversary in a non-leap
# year is considered to have been reached on March 1.
def reached_anniversary_in_year_of(original_date, new_date)
if new_date.month == original_date.month
new_date.day >= original_date.day
else
new_date.month > original_date.month
end
end
Ответ 5
с http://github.com/radar/dotiw
Jack is <%= distance_of_time_in_words (Time.now, Time.local(1950,03,22)) %> old.
произвести
Jack is 60 years old
Ответ 6
вы можете использовать рубиновый камень adroit-age
Он также работает на високосные годы.
age = AdroitAge.find_age("23/01/1990")
Update
require 'adroit-age'
dob = Date.new(1990,1,23)
or
dob = "23/01/1990".to_date
age = dob.find_age
#=> 23
Ответ 7
Та же идея, что и FM, но с упрощенным оператором if. Очевидно, вы могли бы добавить второй аргумент вместо текущего времени.
def age(birthdate)
now = DateTime.now
age = now.year - birthdate.year
age -= 1 if(now.yday < birthdate.yday)
age
end
Ответ 8
Я думаю, что это всегда будет работать, даже для кого-то с днем рождения почти в прыжок:
require 'date'
def calculate_age(start_date, end_date)
end_date.year - start_date.year - ((end_date.month > start_date.month || (end_date.month == start_date.month && end_date.day >= start_date.day)) ? 0 : 1)
end
puts calculate_age( Date.strptime('03/02/1968', '%m/%d/%Y'), Date.strptime('03/02/2010', '%m/%d/%Y'))
Вычисленный возраст с этим методом в приведенном выше примере вызова равен 42, что верно, несмотря на то, что 1968 год является високосным годом, а день рождения близок к скачкообразному дню.
Плюс, таким образом нет необходимости создавать локальную переменную.
Ответ 9
Я придумал следующее, основанное на аналогичных рассуждениях как @FMc
Сначала вычислите разницу между сегодняшним годом и днем рождения. Затем суммируйте его с днем рождения и проверьте полученную дату: если оно больше, чем сегодня, уменьшите diff на 1.
Для использования в приложениях Rails, поскольку он использует метод ActiveSupport
years
def age(birthday, today)
diff = today.year - birthday.year
(birthday + diff.years > today ) ? (diff - 1) : diff
end
Ответ 10
Как насчет чего-то типа:
def years_diff(from_time,to_time)
(((to_time - from_time).abs)/ (365 * 24 * 60 * 60)).to_i
end
years_diff(Time.now,Time.local(1950,03,22)) #=> 59
years_diff(Time.now,Time.local(2009,03,22)) #=> 0
years_diff(Time.now,Time.local(2008,03,22)) #=> 1
Ответ 11
Как насчет этого:
def age_in_years(date)
# Difference in years, less one if you have not had a birthday this year.
today = Date.today
age = today.year - date.year
age = age - 1 if [date.day, date.month, today.year].join('/').to_date > Date.today
end
Ответ 12
d2.year - d1.year - (d2.month > d1.month || (d2.month == d1.month && d2.day >= d1.day) ? 0 : 1)