Rubyで年齢を取得する


125

誕生日から人の年齢を教えてください。now - birthday / 365一部の年には366日あるため、機能しません。私は次のコードを思いつきました:

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

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

年齢を計算するよりRubyっぽい方法はありますか?


6
この質問が好きなのは、「Rubyを増やす」方法と「Rubyを減らす」方法があるという考え方が強調されているからです。論理的に正しいこと(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 2014

1
@ alex0112現在と生年月日の年数の差から、明らかに混乱する条件の結果(0または1)が差し引かれるからです。これは、その人が今年まだ誕生日を迎えているかどうかを調べることを目的としています。そうでない場合は、年の差より1歳年下です。
フィルナッシュ2014

2
@andrej now = Date.todayは機能しますが、タイムゾーンの問題を処理しないことに注意してください。Railsでは、Date.todayはシステムのタイムゾーンに基づいて日付を返します。ActiveRecordは、Apps構成のタイムゾーンに基づいて時間を返します。システムのタイムゾーンがアプリケーションのタイムゾーンと異なる場合、2つの異なるタイムゾーンの時間を効果的に比較することになりますが、これはあまり正確ではありません。
お気に入りのOnwuemene 2016年

これは本当に最も簡単な解決策ですか?
マルコプリンス2016年

50

私はこの解決策がうまく機能し、他の人が読めることを発見しました:

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

簡単で、うるう年などの扱いを気にする必要はありません。


3
これにはRailsが必要です(age.yearsの場合)が、Railsを必要としないようにすることもできますDate.today.month < birthday.month or Date.today.month == birthday.month && Date.today.mday < birthday.mday
チャック、

その通りです。申し訳ありませんが、質問にタグが付けられていたため、Railsを想定しました。しかし、そうです、Ruby専用に簡単に変更できます。
PJ。

1
私は最初にこれを選んだのは、それが最も美しいからです。しかし、本番環境では、私が理解できない理由から、それはしばしば間違っています。上記のTime.now.utc.to_dateを使用した方がうまく機能しているようです。
ケビン

@ケビン興味深い。私自身はこれで問題が発生したことはありませんが、問題がないという意味ではありません。具体的な例を教えていただけますか?バグがあるかどうか知りたいのですが。ありがとう。
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がうるう年であり、現在の年がうるう年でない場合は壊れます。大したことではありませんが、問題を引き起こしています。
フィルナッシュ

1
フィルナッシュの答えを奨励する反対投票。
Nick Sonneveld 2014年

2
philnashの回答を好むもう1つの理由は、それが普通のRubyで機能するのに対して、受け入れられた回答はでのみ機能することrails/activesupportです。
sheldonh

16

Ruby on Rails(ActiveSupport)の1つのライナー。うるう年、うるう秒などを扱います。

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、Rubyはとにかく「うるう秒」をサポートしていません)。:-)
Vikrant Chaudhary、2011年

1
なぜこれに反対票を投じているのかわからない。説明してください、親愛なる投票者ですか?
Vikrant Chaudhary 2013

@vikrantChaudharyわからないけど、いい答えです。テストされ、動作します。
Hector Ordonez 2015年

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

したがって、これは基本的に、各月が100日間で、各年が100か月である場合の日数の差を計算します。これは、年の部分だけを保持している場合には違いがありません。
ジョナサンアラード2018

6

これまでの答えはちょっと変です。あなたの最初の試みはこれを行う正しい方法にかなり近かったです:

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

小数の結果が得られるので、結果をで整数に変換してくださいto_i。これは、イベント以降の日数の差を日数(または関連するTimeクラスの場合は秒数)で測定される期間として正しく処理するため、より優れたソリューションです。次に、1年の日数で単純に除算すると、年齢がわかります。この方法で年数を計算する場合、元のDOB値を保持している限り、うるう年を考慮に入れる必要はありません。


誕生日= Time.mktime(1960,5,5)が範囲外(エポックの問題?)
Andrew Grimm

ええ、エポックの問題に行きます。これを解決するために答えを更新しました。
ボブ・アマン

birthday = DateTime.now - 1.year年齢は0です。残念ながら、365.25で割ると少し不正確になります。
Samir Talwar、

そのような1.yearをDateTimeオブジェクトから減算することはできません。1.yearは、1年の秒数に解決されます。DateTimeオブジェクトは日に基づいて動作します。次に例を示します。(DateTime.now-365.25).strftime( "%D")精度については、誕生日のみを処理している場合は、かなり正確です。問題の事実は、人々はそれが年齢になるとすでにかなり不正確です。私たちは正確な瞬間に生まれますが、通常、DOBを書き留めるときに、正確な時間、分、秒を出産しません。ここでの私の主張は、この計算を手動で実行したくないということです。
ボブ・アマン

1
これは、1900年より前に生まれた人には機能しません。たとえば、ガートルードベインズは、2009
Andrew Grimm

6

私のおすすめ:

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

トリックは、Timeを使用したマイナス操作が秒を返すことです。


これはほぼ正しいです。うるう年とは、1年が実際には365.25日であることを意味します。つまり、この方法ではせいぜい、誕生日から18時間経過するまで年齢が増加しない可能性があります。
Ryan Lue 2017年

5

私はこれが好きです:

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

これがすでに10個の回答がある3年間の質問に対する妥当な候補であると考える場合は、個人的な好みよりも多くの理由を含める必要があります。そうでなければ、あなたはあまり注目されません
John Dvorak

1
これは、ある年がうるう年で別の年がそうでない場合は壊れます
artm

最後の2月が29日である場合、この計算は失敗します
phil88530

5

この回答が最善です。代わりに賛成してください。


@philnashのソリューションは好きですが、条件付きの方がコンパクトになる可能性があります。そのブール式が行うことは、辞書式順序を使用して[月、日]のペアを比較することです。そのため、代わりにルビーの文字列比較を使用できます。

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 2017年

うわー、それはとてもすっきりしている。あなたは答えを出し、報酬を集めるべきです!
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 2014

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

適切なモデルにDateHelperを含めて、distance_of_time_in_wordsおよびdistance_of_time_in_words_hashにアクセスします。この例では、モデルは「User」であり、誕生日フィールドは「birthday」です。

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。このメソッドは文字列を使用して今年の誕生日より前かどうかを判断するため、これは他の回答とは異なります。

たとえばdobtodayが2004/2/28で2014/2/28の場合、age2014 - 2004またはになります10。フロートになります02280229b4bdayなります"0228" < "0229"true。最後に、1から減算しageて取得し9ます。

これは、2つの時間を比較する通常の方法です。

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プロジェクトでその方法を使用したと述べた。タグにレールがありました。彼の方法には、私の方法よりも2つの比較があります。彼の方法の最後の行は理解するのが難しいです。
Cruz Nunez

申し訳ありませんが、philnashのコードはあなたのコードよりもはるかにクリーンです。また、彼のコードは単純な方法です。あなたは「ドブ」の価値を持つことに依存しています。これは、新規ユーザーにはそれほど明確ではないかもしれません。そして、コードをあまり助けません。はい、あなたの最後のサンプルはそれを取り除きます。しかし、philnashのコードは、完全に単純で愚かなコードに最適です。
Mantas 2016

0

を使用して1年の正確な日を取得できるため、月を数えない方が多くなると思います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

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

うるう年を考慮に入れるには(およびactivesupportの存在を想定):

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.