Получить возраст человека в рубине - PullRequest
120 голосов
/ 04 мая 2009

Я бы хотел узнать возраст человека с дня рождения. now - birthday / 365 не работает, потому что у некоторых лет есть 366 дней. Я придумал следующий код:

now = Date.today
year = now.year - birth_date.year

if (date+year.year) > now
  year = year - 1
end

Есть ли более рубиновый способ подсчета возраста?

Ответы [ 23 ]

1 голос
/ 14 марта 2019

Я считаю, что это функционально эквивалентно ответу @ philnash, но IMO более легко понять.

class BirthDate
  def initialize(birth_date)
    @birth_date = birth_date
    @now = Time.now.utc.to_date
  end

  def time_ago_in_years
    if today_is_before_birthday_in_same_year?
      age_based_on_years - 1
    else
      age_based_on_years
    end
  end

  private

  def age_based_on_years
    @now.year - @birth_date.year
  end

  def today_is_before_birthday_in_same_year?
    (@now.month < @birth_date.month) || ((@now.month == @birth_date.month) && (@now.day < @birth_date.day))
  end
end

Использование:

> BirthDate.new(Date.parse('1988-02-29')).time_ago_in_years
 => 31 
1 голос
/ 23 октября 2013

Поскольку Ruby on Rails помечен, гем dotiw переопределяет встроенный в Rails distance_of_times_in_words и предоставляет distance_of_times_in_words_hash , который можно использовать для определения возраста. Високосные годы хорошо обрабатываются для части лет, хотя имейте в виду, что 29 февраля действительно влияет на часть дней, которая требует понимания, необходим ли такой уровень детализации. Кроме того, если вам не нравится, как dotiw меняет формат distance_of_time_in_words, используйте параметр: vague, чтобы вернуться к исходному формату.

Добавить файл в Gemfile:

gem 'dotiw'

В командной строке:

bundle

Включите DateHelper в соответствующую модель, чтобы получить доступ к distance_of_time_in_words и distance_of_time_in_words_hash. В этом примере модель - «Пользователь», а поле дня рождения - «день рождения».

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

Использование:

u = User.new("birthday(1i)" => "2011", "birthday(2i)" => "10", "birthday(3i)" => "23")
u.age
0 голосов
/ 09 июня 2019

DateHelper можно использовать только для получения лет

puts time_ago_in_words '1999-08-22'

почти 20 лет

0 голосов
/ 21 июня 2018

Придумал вариант Rails этого решения

def age(dob)
    now = Date.today
    age = now.year - dob.year
    age -= 1 if dob > now.years_ago(age)
    age
end
0 голосов
/ 08 февраля 2018

Вот мое решение, которое также позволяет рассчитать возраст на определенную дату:

def age on = Date.today
  (_ = on.year - birthday.year) - (on < birthday.since(_.years) ? 1 : 0)
end
0 голосов
/ 08 октября 2017

Я думаю, что лучше не считать месяцы, потому что вы можете получить точный день года, используя Time.zone.now.yday.

def age
  years  = Time.zone.now.year - birthday.year
  y_days = Time.zone.now.yday - birthday.yday

  y_days < 0 ? years - 1 : years
end
0 голосов
/ 30 октября 2016

Хорошо, как насчет этого:

def age
  return unless dob
  t = Date.today
  age = t.year - dob.year
  b4bday = t.strftime('%m%d') < dob.strftime('%m%d')
  age - (b4bday ? 1 : 0)
end

Это предполагает, что мы используем рельсы, вызываем метод age для модели, и модель имеет столбец базы данных дат dob. Это отличается от других ответов, поскольку этот метод использует строки, чтобы определить, не наступили ли мы до дня рождения в этом году.

Например, если dob - 2004/2/28, а today - 2014/2/28, age будет 2014 - 2004 или 10. Поплавки будут 0228 и 0229. b4bday будет "0228" < "0229" или true. Наконец, мы вычтем 1 из age и получим 9.

Это будет нормальный способ сравнения двух раз.

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

??

0 голосов
/ 14 февраля 2015

Если вам наплевать на день или два, это будет короче и довольно очевидно.

(Time.now - Time.gm(1986, 1, 27).to_i).year - 1970
0 голосов
/ 04 октября 2009

Следующее, кажется, работает (но я был бы признателен, если бы оно было проверено).

age = now.year - bday.year
age -= 1 if now.to_a[7] < bday.to_a[7]
0 голосов
/ 14 июля 2013

Для учета високосных лет (и при условии наличия активной поддержки):

def age
  return unless birthday
  now = Time.now.utc.to_date
  years = now.year - birthday.year
  years - (birthday.years_since(years) > now ? 1 : 0)
end

years_since правильно изменит дату, чтобы учесть не високосные годы (когда день рождения 02-29).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...