i know it’s probably really simple, how do i work out someone’s age if i
have their d.o.b. stored as a date in my db.
cheers
i know it’s probably really simple, how do i work out someone’s age if i
have their d.o.b. stored as a date in my db.
cheers
Depending on your database, how about doing something with the
datediff() or
similar function? eg: for Postgresql:
select (current_timestamp-dob) / 365.25 from users
I’m sure you could
irb(main):001:0> require ‘date’
=> true
irb(main):002:0> bday = Date.new(1985, 7, 24)
=> #<Date: 4892541/2,0,2299161>
irb(main):003:0> age = (Date.today - bday).to_i / 365
=> 20
This is ruby, so there’s probably a better way. There should be some
slick way of doing it like
bday.years.until(Date.today) # This does not work. But I think it’d
be cool if it did
Pat
Two things to think about:
In Rails, database is for stoiring raw data, not for calculations.
There is nothing wrong in using it for calculations when you have some
good reason to do so, but by default you shouldn’t do it.
days/365, as well as days/365.25 are both approximations (the former
is wrong more often than the latter). Sure, we can do better than that!
So, how about below?
Alex
require ‘test/unit’
class BirthdayTest < Test::Unit::TestCase
def test_simple
assert_equal 100, age(Date.new(1905, 1, 1), Date.new(2005, 1, 1))
end
def test_age_born_this_year_is_zero
assert_equal 0, age(Date.new(2005, 1, 1), Date.new(2005, 12, 31))
assert_equal 1, age(Date.new(2005, 1, 1), Date.new(2006, 1, 1))
end
def test_doesnt_like_negative_age
birthdate = Date.new(2005, 1, 2)
day_before_birthdate = birthdate - 1
assert_raises(RuntimeError) { age(birthdate, day_before_birthdate)
}
end
def test_works_well_when_birthday_already_passed_this_year
assert_equal 9, age(Date.new(1990, 2, 2), Date.new(2000, 2, 1))
assert_equal 10, age(Date.new(1990, 2, 2), Date.new(2000, 2, 2))
end
def test_handles_feb_29
assert_equal 4, age(Date.new(2000, 2, 29), Date.new(2005, 2, 28))
assert_equal 5, age(Date.new(2000, 2, 29), Date.new(2005, 3, 1))
end
def test_handles_many_years
assert_equal 6000, age(Date.new(-3000, 1, 1), Date.new(3000, 12,
31))
end
end
def age(birthdate, now)
raise “Birthdate (#{birthdate.strftime(’%Y-%m-%d’)}) is after now
(#{now.strftime(’%Y-%m-%d’)})” if birthdate > now
had_birthday_passed_this_year = (now.month * 100 + now.day >=
birthdate.month * 100 + birthdate.day)
if had_birthday_passed_this_year
now.year - birthdate.year
else
now.year - birthdate.year - 1
end
end
Weird, I was just writing something like this in the course of
learning ruby. I doubt you’ll learn anything by just posting a random
question and expecting an answer. You should at least give it a stab.
Hopefully, a more experienced ruby programmer will give me advice to
improve my code.
Here’s my attempt:
birthday.rb code
require “time”
class Birthday
#This can be slimmed down considerably
#but I thought it might be useful to keep them all separate
def initialize(birth_month, birth_date, birth_year)
@birth_month = birth_month
@birth_date = birth_date
@birth_year = birth_year
end
#This puts the birthday in a format that can be manipulated
def bday
bday = @birth_month + “/” + @birth_date + “/” + @birth_year
Time.parse(bday)
end
#This will round off the age
def age
age = ((Time.now - self.bday)/60/60/24/365).to_i
end
end
If you load this from irb using irb> load ‘birthday.rb’
you can put in
irb> john = Birthday.new(“1”, “1”, “1984”)
irb> john.age
Am Sonntag, den 22.01.2006, 21:33 -0700 schrieb Alexey V.:
end
end
I made a small enhancement for the Date class from it:
class date
def age(today = self.class.today)
today.year - year - ((today.month * 100 + today.day >= month * 100 +
day) ? 0 : 1)
end
end
If no attribute is passed, it calculates the age for today. You can pass
a Date object to calculate the age on a specific date.
–
Norman T.
Paul B. wrote:
When I copy the text and save it into a file called BirthdayTest.rb
and then try to run it, I get these errors. It seems like Date.new
doesn’t like having 3 arguments. I am using Ruby 1.8.2 on Win XP.
Any idea why this is?
Hmm… worksforme ™
C:\eclipse\workspace\i2>ruby -v
ruby 1.8.2 (2004-12-25) [i386-mswin32]
C:\eclipse\workspace\i2>irb
irb(main):001:0> Date.new(2000, 1, 1)
=> #<Date: 4903089/2,0,2299161>
C:>age
Loaded suite C:/age
Started
…
Finished in 0.031 seconds.
6 tests, 9 assertions, 0 failures, 0 errors
Alex
Weird…
E:\home\pbarry\projects\rails>ruby -v
ruby 1.8.2 (2004-12-25) [i386-mswin32]
E:\home\pbarry\projects\rails>irb
irb(main):001:0> Date.new(2000,1,1)
ArgumentError: wrong number of arguments (3 for 0)
from (irb):1:in initialize' from (irb):1:in
new’
from (irb):1
When I copy the text and save it into a file called BirthdayTest.rb and
then
try to run it, I get these errors. It seems like Date.new doesn’t like
having 3 arguments. I am using Ruby 1.8.2 on Win XP. Any idea why this
is?
Loaded suite BirthdayTest
Started
EEEEEE
Finished in 0.0 seconds.
Error:
test_age_born_this_year_is_zero(BirthdayTest):
ArgumentError: wrong number of arguments (3 for 0)
BirthdayTest.rb:9:in initialize' BirthdayTest.rb:9:in
new’
BirthdayTest.rb:9:in `test_age_born_this_year_is_zero’
Error:
test_doesnt_like_negative_age(BirthdayTest):
ArgumentError: wrong number of arguments (3 for 0)
BirthdayTest.rb:14:in initialize' BirthdayTest.rb:14:in
new’
BirthdayTest.rb:14:in `test_doesnt_like_negative_age’
Error:
test_handles_feb_29(BirthdayTest):
ArgumentError: wrong number of arguments (3 for 0)
BirthdayTest.rb:25:in initialize' BirthdayTest.rb:25:in
new’
BirthdayTest.rb:25:in `test_handles_feb_29’
Error:
test_handles_many_years(BirthdayTest):
ArgumentError: wrong number of arguments (3 for 0)
BirthdayTest.rb:30:in initialize' BirthdayTest.rb:30:in
new’
BirthdayTest.rb:30:in `test_handles_many_years’
Error:
test_simple(BirthdayTest):
ArgumentError: wrong number of arguments (3 for 0)
BirthdayTest.rb:5:in initialize' BirthdayTest.rb:5:in
new’
BirthdayTest.rb:5:in `test_simple’
Error:
test_works_well_when_birthday_already_passed_this_year(BirthdayTest):
ArgumentError: wrong number of arguments (3 for 0)
BirthdayTest.rb:20:in initialize' BirthdayTest.rb:20:in
new’
BirthdayTest.rb:20:in
`test_works_well_when_birthday_already_passed_this_year’
6 tests, 0 assertions, 0 failures, 6 errors
On 1/23/06, SB [email protected] wrote:
Weird, I was just writing something like this in the course of
learning ruby. I doubt you’ll learn anything by just posting a random
question and expecting an answer. You should at least give it a stab.Hopefully, a more experienced ruby programmer will give me advice to
improve my code.Here’s my attempt:
birthday.rb code
require “time”
I would not recommend using the class time here since it does not
handle dates before 1970-01-01:
irb> Time.parse(“1970-01-01 01:00”)
=> Thu Jan 01 01:00:00 W. Europe Standard Time 1970
irb> Time.parse(“1969-12-31”)
ArgumentError: time out of range
irb> Time.parse(“1970-01-01 00:59”)
ArgumentError: time out of range
Try the Date in date.rb instead.
http://www.ruby-doc.org/core/files/lib/date_rb.html
Something like this looks like it works:
born=Date.strptime(“1969-07-21”)
age=Date.today.year-born.year
age=age-1 if Date.today.yday<born.yday
–
Jonas
Elfström
Using ‘require “time”’ works fine on my computer (Mac OSX). Jan 1,
1970 is the epoch used in the Time class of ruby and might cause
trouble on other operating systems (according to the pickaxe).
However, I agree that using the Date library will probably make my
code more compact and offer more options.
Thanks for pointing this out.
Sam
Neatest method I found was posted by Justing in the forum, not so long
ago :
http://wrath.rubyonrails.org/pipermail/rails/2005-December/006145.html
def age_at(date, dob)
day_diff = date.day - dob.day
month_diff = date.month - dob.month - (day_diff < 0 ? 1 : 0)
date.year - dob.year - (month_diff < 0 ? 1 : 0)
end
Am Dienstag, den 24.01.2006, 01:17 -0500 schrieb Paul B.:
from (irb):1
On my Ubuntu i have to require ‘date’, before i can use it.
irb(main):001:0> Date.new(2006,1,1)
NameError: uninitialized constant Date
from (irb):1
irb(main):002:0> require ‘date’
=> true
irb(main):003:0> Date.new(2006,1,1)
=> #<Date: 4907473/2,0,2299161>
irb(main):004:0>
Maybe this helps.
–
Norman T.
On 1/24/06, Alan [email protected] wrote:
Neatest method I found was posted by Justing in the forum, not so long
ago :
http://wrath.rubyonrails.org/pipermail/rails/2005-December/006145.htmldef age_at(date, dob)
day_diff = date.day - dob.day
month_diff = date.month - dob.month - (day_diff < 0 ? 1 : 0)
date.year - dob.year - (month_diff < 0 ? 1 : 0)
end
Sorry, could not help myself:
def age_at(date, dob)
date.year - dob.year - ( (date.yday-dob.yday) < 0 ? 1 : 0 )
end
And now something for the swedish readers. Check out my validation of
swedish “social security number” in Ruby:
http://plea.se/me/validatePnum.html
–
Jonas
Elfström
So my desktop has the problem as listed in the previous email, but it
seems
to work on my laptop fine:
C:\Documents and Settings\PBarry>ruby -v
ruby 1.8.2 (2004-12-25) [i386-mswin32]
C:\Documents and Settings\PBarry>irb
irb(main):001:0> Date.new(2000,1,1)
=> #<Date: 4903089/2,0,2299161>
But on linux, it doesn’t work:
[root@paulbarry ~]# ruby -v
ruby 1.8.4 (2005-12-24) [i386-linux]
[root@paulbarry ~]# irb
irb(main):001:0> Date.new(2000,1,1)
NameError: uninitialized constant Date
from (irb):1
Any idea what could cause these differences? 3 different environments,
three different results for the same 1 line of code. Kind of makes me
worried that code I write on one machine will not work on another.
On 1/24/06, Paul B. [email protected] wrote:
I believe this would techincally not work in leap year, right?
Why not? yday is 1 to 366 in a leap year.
I tested a few dates in and out of leap years and it seems to work
just fine. If you find a case that breaks the functionality please
tell me. Maybe we should take it offlist…
–
/J
month_diff = date.month - dob.month - (day_diff < 0 ? 1 : 0)
date.year - dob.year - (month_diff < 0 ? 1 : 0)
endSorry, could not help myself:
def age_at(date, dob)
date.year - dob.year - ( (date.yday-dob.yday) < 0 ? 1 : 0 )
end
–
Jonas
Elfström
On 1/24/06, Paul B. [email protected] wrote:
But on linux, it doesn’t work:
[root@paulbarry ~]# irb
irb(main):001:0> Date.new(2000,1,1)
NameError: uninitialized constant Date
from (irb):1Any idea what could cause these differences?
Somehow the date class is preloaded in some of your installations and
in some not, I leave the story behind that to the wizards. Always do:
require ‘date.rb’
and you will be fine in any environment.
–
Jonas
Elfström
I believe this would techincally not work in leap year, right?
This shows the errors in age_at better:
require ‘test/unit’
class BirthdayTest < Test::Unit::TestCase
def test_age_at_non_leap_year_with_leap_year_dob
assert_equal 19, age_at(Date.new(2007, 3, 1), Date.new(1988, 3, 1))
end
def test_age_at_leap_year_with_non_leap_year_dob
assert_equal 20, age_at(Date.new(2008, 2, 29), Date.new(1987, 3, 1))
end
def test_age_non_leap_year_with_leap_year_dob
assert_equal 19, age(Date.new(2007, 3, 1), Date.new(1988, 3, 1))
end
def test_age_leap_year_with_non_leap_year_dob
assert_equal 20, age(Date.new(2008, 2, 29), Date.new(1987, 3, 1))
end
end
def age_at(date, dob)
date.year - dob.year - ( (date.yday-dob.yday) < 0 ? 1 : 0 )
end
def age(now, birthdate)
had_birthday_passed_this_year = (now.month * 100 + now.day >=
birthdate.month * 100 + birthdate.day)
if had_birthday_passed_this_year
now.year - birthdate.year
else
now.year - birthdate.year - 1
end
end
it doesn’t work because Date.new(2008,3,1).yday is 61, whereas
Date.new(2007,3,1).yday
is 60. Looks like Alekexy’s age method is correct and the age_at method
that relies on yday is incorrect:
require ‘test/unit’
class BirthdayTest < Test::Unit::TestCase
def test_age_at_non_leap_year_with_leap_year_dob
assert_equal 19, age_at(Date.new(2007, 3, 1), Date.new(1988, 3, 1))
end
def test_age_at_leap_year_with_leap_year_dob
assert_equal 20, age_at(Date.new(2008, 3, 1), Date.new(1988, 3, 1))
end
def test_age_at_non_leap_year_with_non_leap_year_dob
assert_equal 20, age_at(Date.new(2007, 3, 1), Date.new(1987, 3, 1))
end
def test_age_at_leap_year_with_non_leap_year_dob
assert_equal 21, age_at(Date.new(2008, 3, 1), Date.new(1987, 3, 1))
end
def test_age_non_leap_year_with_leap_year_dob
assert_equal 19, age(Date.new(2007, 3, 1), Date.new(1988, 3, 1))
end
def test_age_leap_year_with_leap_year_dob
assert_equal 20, age(Date.new(2008, 3, 1), Date.new(1988, 3, 1))
end
def test_age_non_leap_year_with_non_leap_year_dob
assert_equal 20, age(Date.new(2007, 3, 1), Date.new(1987, 3, 1))
end
def test_age_leap_year_with_non_leap_year_dob
assert_equal 21, age(Date.new(2008, 3, 1), Date.new(1987, 3, 1))
end
end
def age_at(date, dob)
date.year - dob.year - ( (date.yday-dob.yday) < 0 ? 1 : 0 )
end
def age(now, birthdate)
had_birthday_passed_this_year = (now.month * 100 + now.day >=
birthdate.month * 100 + birthdate.day)
if had_birthday_passed_this_year
now.year - birthdate.year
else
now.year - birthdate.year - 1
end
end
This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.
Sponsor our Newsletter | Privacy Policy | Terms of Service | Remote Ruby Jobs