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 -- Posted via http://www.ruby-forum.com/.
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 On 1/23/06, pd <pd@gmail.com> wrote:> > 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 > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060123/4460fa67/attachment-0001.html
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 On 1/22/06, pd <pd@gmail.com> wrote:> 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 > > -- > Posted via http://www.ruby-forum.com/. > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
Two things to think about: 1. 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. 2. 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 Verkhovsky:> 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 > endI 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 Timmler http://blog.inlet-media.de
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. 1) 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'' 2) 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'' 3) 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'' 4) 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'' 5) 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'' 6) 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/22/06, Alexey Verkhovsky <alex@verk.info> wrote:> > Two things to think about: > > 1. 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. > > 2. 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 > > > > > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060124/0ce3aabb/attachment.html
Paul Barry 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 (TM) 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 On 1/24/06, Alexey Verkhovsky <alex@verk.info> wrote:> > Paul Barry 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 (TM) > > 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 > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060124/82aedd0d/attachment-0001.html
Am Dienstag, den 24.01.2006, 01:17 -0500 schrieb Paul Barry:> 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 >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 Timmler http://blog.inlet-media.de
On 1/23/06, SB <richstyles@gmail.com> 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 On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com> wrote:> On 1/23/06, SB <richstyles@gmail.com> 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 > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >
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 -- Posted via http://www.ruby-forum.com/.
On 1/24/06, Alan <alan@incrediblinc.com> 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.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) > endSorry, 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
I believe this would techincally not work in leap year, right? On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com> wrote:> > On 1/24/06, Alan <alan@incrediblinc.com> 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.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 > > 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 > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060124/42dd9a05/attachment.html
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 Barry <mail@paulbarry.com> wrote:> > 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 > > On 1/24/06, Alexey Verkhovsky <alex@verk.info> wrote: > > > > Paul Barry 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 (TM) > > > > 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 > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060124/660ae3f2/attachment-0001.html
On 1/24/06, Paul Barry <mail@paulbarry.com> 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> On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com> wrote: > > > > On 1/24/06, Alan <alan@incrediblinc.com > 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.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 > > > > Sorry, 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 Barry <mail@paulbarry.com> 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):1 > > Any 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
A friend, <http://lathi.net/>Doug <http://lathi.net/>Alcorn, had a similar problem and wrote about the results. http://blog.lathi.net/articles/2006/01/05/how-old-are-you Basically, <http://onestepback.org/>Jim Weirich posted the code here: http://rafb.net/paste/results/rL4Dt798.html Of course, Jim includes a full test suite, too. ;-) -Rob At 1/24/2006 11:25 AM, Jonas Elfstr?m wrote:>On 1/24/06, Paul Barry <mail@paulbarry.com> 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 > > > On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com> wrote: > > > > > > On 1/24/06, Alan <alan@incrediblinc.com > 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.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 > > > > > > Sorry, could not help myself: > > > > > > def age_at(date, dob) > > > date.year - dob.year - ( (date.yday-dob.yday) < 0 ? 1 : 0 ) > > > end > >-- >Jonas Elfstr?m >_______________________________________________ >Rails mailing list >Rails@lists.rubyonrails.org >http://lists.rubyonrails.org/mailman/listinfo/rails-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060124/ccf833e3/attachment.html
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 On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com> wrote:> > On 1/24/06, Paul Barry <mail@paulbarry.com> 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 > > > On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com> wrote: > > > > > > On 1/24/06, Alan <alan@incrediblinc.com > 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.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 > > > > > > Sorry, could not help myself: > > > > > > def age_at(date, dob) > > > date.year - dob.year - ( (date.yday-dob.yday) < 0 ? 1 : 0 ) > > > end > > -- > Jonas Elfstr?m > _______________________________________________ > Rails mailing list > Rails@lists.rubyonrails.org > http://lists.rubyonrails.org/mailman/listinfo/rails >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060124/7068290c/attachment.html
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 On 1/24/06, Paul Barry <mail@paulbarry.com> wrote:> > 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 > > On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com> wrote: > > > > On 1/24/06, Paul Barry <mail@paulbarry.com> 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 > > > > > On 1/24/06, Jonas Elfstr?m <jonelf@gmail.com > wrote: > > > > > > > > On 1/24/06, Alan <alan@incrediblinc.com > 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.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 > > > > > > > > Sorry, could not help myself: > > > > > > > > def age_at(date, dob) > > > > date.year - dob.year - ( (date.yday-dob.yday) < 0 ? 1 : 0 ) > > > > end > > > > -- > > Jonas Elfstr?m > > _______________________________________________ > > Rails mailing list > > Rails@lists.rubyonrails.org > > http://lists.rubyonrails.org/mailman/listinfo/rails > > > >-------------- next part -------------- An HTML attachment was scrubbed... URL: http://wrath.rubyonrails.org/pipermail/rails/attachments/20060124/4ff1f5a0/attachment.html
On 1/24/06, Paul Barry <mail@paulbarry.com> wrote:> This shows the errors in age_at better:Thanks for pointing this out! I can''t imagine why I did not think of this. I am not in any way an endorser of trying to make code as short as possible but out of curiosity I fixed my one-line class so that it now correct but "unreadable": def age_at(date, dob) date.year - dob.year - (date.month-dob.month < 0 ? 1 : date.day-dob.day < 0 ? 1:0) end -- Jonas Elfstr?m
Am Montag, den 23.01.2006, 17:05 +0100 schrieb Norman Timmler:> 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 > endI cleaned it a up a bit and made it more readable: class Date def age(base = self.class.today) base.year - year - ((base.month * 100 + base.day >= month * 100 + day) ? 0 : 1) end end Use it like that: # to get the age for today Date.new(1978,4,20).age # to get the age for January, the 1st, 2020 Date.new(1978,4,20).age(Date.new(2020,1,1)) You can validate the age of a person in this simple way: class Person < ActiveRecord::Base validates_inclusion_of :age, :in=>18..99 def age # expecting that you have an attribute ''date_of_birth'' # filled with a Date object date_of_birth.age end end -- Norman Timmler http://blog.inlet-media.de
Here is a little bit i just put together. I''ve not made it pretty and have only done some basic testing. Context: this function is in a model which has a Date field called dob it returns the age in "y years m months d days old" format skipping values that are empty and pluralizing year month and day as appropriate. ex: (Time.now = 2006/01/28) dob [time_ago_in_words] [object.age_in_words] 2004-02-21 (age = 707 days) (1 year 11 months 7 days old) 2002-01-28 (age = 1461 days) (4 years old) 2005-08-20 (age = 161 days) (5 months 8 days old) ========================== def age_in_words if dob == nil "--" else now = Time.now ydiff = now.year - dob.year mdiff = now.month - dob.month ddiff = now.day - dob.day if ((mdiff < 0) && (ydiff > 0)) y = ydiff - 1 m = mdiff + 12 else y = ydiff m = mdiff end if ((ddiff < 0) && (mdiff != 0)) m = m - 1 dim = Time.days_in_month(dob.month+m,dob.year+y) d = (dim - dob.day) + now.day else d = ddiff end end ys = "year" ms = "month" ds = "day" if (y.abs > 1) ys= ys.pluralize end if (m.abs > 1) ms = ms.pluralize end if (d.abs > 1) ds = ds.pluralize end year_string = (y != 0)?"#{y} #{ys} ":"" month_string = (m != 0)?"#{m} #{ms} ":"" day_string = (d != 0)?"#{d} #{ds}":"" return "#{year_string}#{month_string}#{day_string} old" end -- Posted via http://www.ruby-forum.com/.