루비에서 사람의 나이를 얻으십시오


125

생일부터 사람의 나이를 받고 싶습니다. now - birthday / 365몇 년 동안 366 일이 있기 때문에 작동하지 않습니다. 다음 코드를 생각해 냈습니다.

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

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

나이를 계산하는 더 많은 Ruby'ish 방법이 있습니까?


6
이 질문은 "더 많은 루비"와 "루비가 적은"방법이 있다는 아이디어를 강조하기 때문에 좋아합니다. 논리적으로 정확해야 할뿐만 아니라 (C # 답변을 복사하여 가능) 스타일 적으로도 중요합니다. 그리고 Adinochestva의 답변은 Ruby 관용구를 잘 활용합니다.
James A. Rosen

답변:


410

나는 여기서 파티에 늦었다는 것을 알고 있지만, 윤년에 2 월 29 일에 태어난 사람의 나이를 운동하려고 할 때 받아 들여지는 대답은 끔찍하게 깨질 것입니다. 호출 birthday.to_date.change(:year => now.year)날짜가 잘못 되었기 때문 입니다.

대신 다음 코드를 사용했습니다.

require 'date'

def age(dob)
  now = Time.now.utc.to_date
  now.year - dob.year - ((now.month > dob.month || (now.month == dob.month && now.day >= dob.day)) ? 0 : 1)
end

4
윤년을 처리 할 수없는 체크 표시가 아닌 이것을 사용하십시오
bgcode

왜 0을 반환합니까? true|| 대신 1 false?
0112

1
@ alex0112 인정되는 혼란스러운 조건부 결과의 결과 (0 또는 1)가 현재와 생년월일 간의 연도 차이에서 빼기 때문입니다. 그 사람이 올해 아직 생일을했는지 ​​여부를 알아보고 그렇지 않은 경우에는 연령 차이보다 1 살이 적습니다.
philnash

2
@andrej now = Date.today는 작동하지만 시간대 문제는 처리하지 않습니다. In Rails Date.today는 시스템 시간대를 기준으로 날짜를 반환합니다. ActiveRecord는 앱 구성 시간대를 기반으로 시간을 반환합니다. 시스템 시간대가 응용 프로그램 시간대와 다른 경우 두 개의 서로 다른 시간대의 시간을 효과적으로 비교하는 것이 매우 정확하지 않습니다.
좋아하는 Onwuemene

이것이 가장 간단한 해결책입니까?
Marco Prins

50

이 솔루션이 잘 작동하고 다른 사람들이 읽을 수있는 것으로 나타났습니다.

    age = Date.today.year - birthday.year
    age -= 1 if Date.today < birthday + age.years #for days before birthday

쉽고 당신은 윤년 등을 처리에 대해 걱정할 필요가 없습니다.


3
레일즈 (나이. 년)가 필요하지만, 같은 일을한다면 레일을 요구하지 않을 수 있습니다 Date.today.month < birthday.month or Date.today.month == birthday.month && Date.today.mday < birthday.mday.
Chuck

맞습니다. 질문에 태그가 추가되어 Rails로 가정했습니다. 그러나 루비에 대해서만 쉽게 수정됩니다.
PJ.

1
나는 이것이 가장 예쁘기 때문에 처음에 이것을 선택했지만, 프로덕션에서는 종종 틀리지 않습니다. Time.now.utc.to_date를 사용하는 위의 것이 더 잘 작동하는 것 같습니다.
케빈

@Kevin 재미있는. 나는 이것에 대해 아무런 문제가 없었지만 이것이 없다는 것을 의미하지는 않는다. 구체적인 예를 들어 주시겠습니까? 버그가 있는지 알고 싶습니다. 감사.
PJ.

2
@sigvei-버그가 아닌 기능입니다.) 미국을 포함한 대부분의 국가에서 28 번째는 윤년이 아닌 아기의 경우 윤년이 아닌 생일로 법적으로 간주됩니다. 그 사람은 실제로 10으로 간주 될 것입니다.
PJ.

33

이것을 사용하십시오 :

def age
  now = Time.now.utc.to_date
  now.year - birthday.year - (birthday.to_date.change(:year => now.year) > now ? 1 : 0)
end

41
birthday.to_date가 윤년이고 현재 연도가 아닌 경우 중단됩니다. 큰 일이 아니지만 문제가되었습니다.
Philnash

1
Philnash의 답변을 장려하기 위해 공감.
Nick Sonneveld

2
philnash의 답변 을 선호하는 또 다른 이유 는 평범한 오래된 Ruby에서 작동하지만 허용 된 답변은에서만 작동하기 때문입니다 rails/activesupport.
sheldonh

16

Ruby on Rails (ActiveSupport)의 하나의 라이너. 윤년, 윤초 등을 처리합니다.

def age(birthday)
  (Time.now.to_s(:number).to_i - birthday.to_time.to_s(:number).to_i)/10e9.to_i
end

여기에서 논리 -C #에서 나이 계산

호출 할 경우 두 날짜, 같은 시간대에 가정 utc()전에 to_s()모두.


1
(Date.today.to_s(:number).to_i - birthday.to_date.to_s(:number).to_i)/1e4.to_i또한 작동
Grant Hutchins

FWIW, 그러나 "윤초"에 대한 보증이 무효화됩니다. ;-) (FWIW 2 부, 루비는 "윤초"를 지원하지 않습니다). :-)
Vikrant Chaudhary

1
왜 내가 이것에 대한 투표를 받고 있는지 확실하지 않습니다. 사랑하는 downvoters 설명해야합니까?
Vikrant Chaudhary

@vikrantChaudhary 모르겠다. 대단한 답변이다. 테스트하고 작동합니다.
헥터 오르도 네즈

9
(Date.today.strftime('%Y%m%d').to_i - dob.strftime('%Y%m%d').to_i) / 10000

따라서 이것은 매월 100 일, 매년 100 개월 인 경우 일의 차이를 계산합니다. 연도 부분 만 유지하면 차이가 없습니다.
Jonathan Allard

6

지금까지의 답변은 다소 이상합니다. 원래 시도는 이것을 수행하는 올바른 방법에 매우 가깝습니다.

birthday = DateTime.new(1900, 1, 1)
age = (DateTime.now - birthday) / 365.25 # or (1.year / 1.day)

소수의 결과를 얻을 수 있으므로을 사용하여 결과를 정수로 자유롭게 변환하십시오 to_i. 이벤트 이후 날짜 차이를 일 (또는 관련 Time 클래스의 경우 초) 단위로 측정 된 시간으로 올바르게 처리하므로 더 나은 솔루션입니다. 그런 다음 일년에 일 수로 간단한 나눗셈을하면 나이가됩니다. 이러한 방식으로 연령을이 방법으로 계산할 때는 원래 DOB 값을 유지하는 한 윤년에 대한 수당을 요구하지 않습니다.


생일 Time.mktime (1960,5,5)이 범위의 날 제공 = (시대의 문제?)
앤드류 그림 형제에게

예, 획기적인 문제를 해결하십시오. 이 문제를 해결하기 위해 답변을 업데이트했습니다.
Bob Aman

birthday = DateTime.now - 1.year불행히도, 365.25로 나누는 것은 조금 정확하지 않습니다.
Samir Talwar

DateTime 객체에서 1 년을 빼기 할 수 없습니다. 1.year는 1 년의 초 수로 확인됩니다. DateTime 개체는 일을 기준으로 작동합니다. 예를 들면 다음과 같습니다. (DateTime.now-365.25) .strftime ( "% D") 정확성과 관련하여 생일을 다루는 경우에는 매우 정확합니다. 문제의 사실은, 사람들은 나이가 들었을 때 이미 매우 부정확하다는 것입니다. 우리는 정확한 순간에 태어 났지만, 일반적으로 DOB를 작성할 때 정확한시, 분, 초를 제공하지는 않습니다. 여기에서의 나의 주장은이 계산을 수동으로하고 싶지 않다는 것입니다.
밥 아만

1
이는 2009 년 그녀의 생일에 114.9979의 나이를 가진 것으로보고 예를 거트루드 베인스를 들어 1900 년 이전에 태어난 사람들을 위해 작동하지 않습니다
앤드류 그림 형제를

6

나의 제안:

def age(birthday)
    ((Time.now - birthday.to_time)/(60*60*24*365)).floor
end

요령은 Time을 사용한 마이너스 연산이 초를 반환한다는 것입니다.


이것은 거의 맞습니다. 윤년은 1 년이 실제로 365.25 일이라는 것을 의미합니다. 즉, 기껏해야이 방법으로 생일까지 18 시간이 될 때까지 나이가 증가하지 않을 수도 있습니다.
Ryan Lue

5

난이게 좋아:

now = Date.current
age = now.year - dob.year
age -= 1 if now.yday < dob.yday

이것이 이미 10 개의 다른 답변을 가지고있는 3yo 질문에 대한 합리적인 경쟁자라고 생각한다면, 개인 취향보다 더 많은 이유를 포함시켜야합니다. 그렇지 않으면, 당신은 많은 관심을받지 않습니다
존 드보락

1
한 해가 윤년이고 다른 해가 아닌 경우
이것은 art art

지난
년도 2

5

이 답변 이 가장 좋습니다. 대신 찬성하십시오.


나는 @philnash의 솔루션을 좋아하지만 조건부는 더 작을 수 있습니다. 부울식이하는 일은 사전 식 순서를 사용하여 [month, day] 쌍을 비교하는 것이므로 루비의 문자열 비교를 대신 사용할 수 있습니다.

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

1
무엇에 대해 (Date.today.strftime('%Y%m%d').to_i - dob.strftime('%Y%m%d').to_i) / 10000?
Ryan Lue

와우, 너무 깔끔해. 당신은 답변을하고 보상을 수집해야합니다!
artm

음, 사실 나는이 대답도 내 전에 이미 있었다 참조
ARTM

아, 이제 나도 ... -_- '
Ryan Lue

4

이것은 이 답변 의 전환입니다 (많은 표를 받았습니다).

# convert dates to yyyymmdd format
today = (Date.current.year * 100 + Date.current.month) * 100 + Date.today.day
dob = (dob.year * 100 + dob.month) * 100 + dob.day
# NOTE: could also use `.strftime('%Y%m%d').to_i`

# convert to age in years
years_old = (today - dob) / 10000

그것은 접근 방식에서 독특하지만 그것이 무엇을하는지 알 때 완벽하게 이해됩니다.

today = 20140702 # 2 July 2014

# person born this time last year is a 1 year old
years = (today - 20130702) / 10000

# person born a year ago tomorrow is still only 0 years old
years = (today - 20130703) / 10000

# person born today is 0
years = (today - 20140702) / 10000  # person born today is 0 years old

# person born in a leap year (eg. 1984) comparing with non-leap year
years = (20140228 - 19840229) / 10000 # 29 - a full year hasn't yet elapsed even though some leap year babies think it has, technically this is the last day of the previous year
years = (20140301 - 19840229) / 10000 # 30

# person born in a leap year (eg. 1984) comparing with leap year (eg. 2016)
years = (20160229 - 19840229) / 10000 # 32

방금 이것이 같은 anser 임을 깨달았습니다
br3nt

1

Ruby on Rails에 태그가 지정되어 있기 때문에 dotiw 젬은 Rails 내장 distance_of_times_in_words를 재정의 하고 연령을 판별하는 데 사용할 수있는 distance_of_times_in_words_hash 를 제공합니다 . 윤년은 연도 부분에서 잘 처리되지만 2 월 29 일은 세부 수준이 필요한지 이해해야하는 일 부분에 영향을 미칩니다. 또한 dotiw가 distance_of_time_in_words의 형식을 변경하는 방법이 마음에 들지 않으면 : vague 옵션을 사용하여 원래 형식으로 되돌립니다.

Gemfile에 dotiw를 추가하십시오 :

gem 'dotiw'

명령 행에서 :

bundle

distance_of_time_in_words 및 distance_of_time_in_words_hash에 액세스하려면 적절한 모델에 DateHelper를 포함하십시오. 이 예에서 모델은 '사용자'이고 생일 필드는 '생일'입니다.

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

1

나는 이것이 기능적으로 @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 

0

다음은 효과가있는 것 같습니다 (그러나 확인하면 감사하겠습니다).

age = now.year - bday.year
age -= 1 if now.to_a[7] < bday.to_a[7]

0

하루나 이틀을 신경 쓰지 않는다면, 이것은 짧고 자명합니다.

(Time.now - Time.gm(1986, 1, 27).to_i).year - 1970

0

이건 어때?

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. 이 방법은 문자열을 사용하여 올해 생일 전에 있는지 확인하기 때문에 다른 답변과 다릅니다.

예를 들어 dob2004/2/28이고 today2014/2/28 인 age경우 2014 - 2004또는 10입니다. 수레는 02280229입니다. 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

👍🏼


참고로, 귀하의 답변은 필라 네시와 논리적으로 동일합니다. 그의 대답은 훨씬 깨끗하고 Rails에 의존하지 않습니다.
Mantas

@Mantas Philnash는 Rails 프로젝트에서이 방법을 사용했다고 말했다. 태그에 레일이 있습니다. 그의 방법은 내 것보다 두 가지 더 많은 비교가 있습니다. 그의 방법의 마지막 줄은 이해하기 어렵다.
Cruz Nunez

미안하지만 필립의 코드는 당신보다 훨씬 깨끗합니다. 또한 그의 코드는 간단한 방법입니다. 당신의 가치는 "dob"에 달려 있습니다. 새로운 사용자에게는 분명하지 않을 수 있습니다. 그리고 코드를 많이 도와 주지도 않습니다. 그렇습니다. 마지막 샘플은 제거됩니다. 그러나 philnash는 간단하고 바보 같은 코드 조각입니다.
Mantas

0

나는 당신이 정확한 일을 얻을 수 있기 때문에 개월을 계산하지 않는 것이 더 좋다고 생각합니다 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

솔루션 의 Rails 변형을 생각해 냈습니다.

def age(dob)
    now = Date.today
    age = now.year - dob.year
    age -= 1 if dob > now.years_ago(age)
    age
end

0

DateHelper는 몇 년 동안 만 사용할 수 있습니다

puts time_ago_in_words '1999-08-22'

거의 20 년


0
  def computed_age
    if birth_date.present?
      current_time.year - birth_date.year - (age_by_bday || check_if_newborn ? 0 : 1)
    else
      age.presence || 0
    end
  end


  private

  def current_time
    Time.now.utc.to_date
  end

  def age_by_bday
    current_time.month > birth_date.month
  end

  def check_if_newborn
    (current_time.month == birth_date.month && current_time.day >= birth_date.day)
  end```

-1
  def birthday(user)
    today = Date.today
    new = user.birthday.to_date.change(:year => today.year)
    user = user.birthday
    if Date.civil_to_jd(today.year, today.month, today.day) >= Date.civil_to_jd(new.year, new.month, new.day)
      age = today.year - user.year
    else
      age = (today.year - user.year) -1
    end
    age
  end

-1
Time.now.year - self.birthdate.year - (birthdate.to_date.change(:year => Time.now.year) > Time.now.to_date ? 1 : 0)

-1

윤년을 설명하고 적극적 지원 존재를 가정 :

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).


-1

특정 날짜의 나이를 계산할 수있는 내 솔루션은 다음과 같습니다.

def age on = Date.today
  (_ = on.year - birthday.year) - (on < birthday.since(_.years) ? 1 : 0)
end

-2

나도 이것을 다루어야했지만 몇 달 동안. 너무 복잡해졌습니다. 내가 생각할 수있는 가장 간단한 방법은 다음과 같습니다.

def month_number(today = Date.today)
  n = 0
  while (dob >> n+1) <= today
    n += 1
  end
  n
end

12 개월로도 동일한 작업을 수행 할 수 있습니다.

def age(today = Date.today)
  n = 0
  while (dob >> n+12) <= today
    n += 1
  end
  n
end

Date 클래스를 사용하여 월을 늘리면 28 일 및 윤년 등을 처리합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.