Как рассчитать, сколько лет прошло с указанной даты в Ruby? - PullRequest
20 голосов
/ 15 декабря 2009

Этот вопрос был здесь для других языков, так что давайте здесь один для Ruby.

Как рассчитать количество полных лет, прошедших с данной даты? Как вы, наверное, догадались, это рассчитать возраст человека автоматически. Наиболее близким является distance_of_time_in_words Rails helper, поэтому следующий шаблон

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 марта 2010 года Джеку должно быть 59 лет, а на следующий день ему должно быть 60 лет. Високосные годы и тому подобное следует учитывать.

Ответы [ 12 ]

39 голосов
/ 15 декабря 2009

Вы хотите, чтобы возраст был таким, каким его обычно понимают люди, или вы ищете точную оценку прошедшего времени? Если первое, нет необходимости беспокоиться о високосных годах и других осложнениях. Вам просто нужно вычислить разницу в годах и уменьшить ее, если у человека еще не было дня рождения в этом году. Если последнее, вы можете преобразовать прошедшие секунды в годы, как предлагали другие ответы.

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)
5 голосов
/ 15 декабря 2009

У меня есть гем / плагин с именем dotiw , у которого есть distance_of_time_in_words_hash, который будет возвращать хэш вроде: { :years => 59, :months => 11, :days => 27 }. Из этого вы можете работать, если он близок к определенному пределу.

5 голосов
/ 15 декабря 2009
require 'date'

def years_since(dt)
    delta = (Date.today - Date.parse(dt)) / 365
    delta.to_i
end
4 голосов
/ 06 марта 2012

Подход, который обрабатывает високосные годы

Всякий раз, когда вы рассчитываете прошедшие годы с даты, вы должны решить, как обращаться с високосным годом. Вот мой подход, который, на мой взгляд, очень удобен для восприятия и позволяет без промедления использовать лишние годы без какой-либо логики «особого случая».

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
3 голосов
/ 23 февраля 2017

Я придумал следующее, основываясь на том же рассуждении, что и @FMc Сначала вычислите разницу между сегодняшним годом и годом рождения. Затем подведите его к дню рождения и проверьте полученную дату: если она больше, чем сегодня, уменьшите разницу на 1. Для использования в приложениях Rails, так как он использует ActiveSupport years метод

def age(birthday, today)
  diff = today.year - birthday.year
  (birthday + diff.years > today ) ? (diff - 1) : diff
end
2 голосов
/ 07 сентября 2013

вы можете использовать рубиновый камень ловкий возраст

Работает и в високосные годы ..

age = AdroitAge.find_age("23/01/1990")

Обновление

require 'adroit-age'

dob =  Date.new(1990,1,23)
or
dob = "23/01/1990".to_date

age = dob.find_age
#=> 23
2 голосов
/ 04 марта 2010

с 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
1 голос
/ 10 марта 2012

Как насчет этого:

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
1 голос
/ 15 января 2010

Я думаю, что это всегда будет работать, даже для тех, у кого день рождения близок к високосному дню:

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 год был високосным, а день рождения близок к високосному.

Кроме того, нет необходимости создавать локальную переменную.

1 голос
/ 17 декабря 2009

Та же идея, что и у FM, но с упрощенным оператором if. Очевидно, вы могли бы добавить второй аргумент вместо использования текущего времени.

def age(birthdate)
  now = DateTime.now
  age = now.year - birthdate.year
  age -= 1 if(now.yday < birthdate.yday)
  age
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...