# age calculation

Hi experts,

I am trying to calculate age in rails.

I did something like this, but I know I am not considering leap years/months.
+++++++++++
class AttendingIp < ActiveRecord::Base
def age

age = age - 1
end

end

end

++++++
I went through ruby api, but didn't find solution. Is there nice way to do this in RoR?

###### Who is Participating?

Information ArchitectCommented:
here is the code, that should already be a lot faster

y_dif = now.year - born.year
if Date.new(now.year - y_dif, now.month, now.day) < born
y_dif = y_dif - 1
end

m_tot = 0
almost_close_date = Date.new(born.year + y_dif, born.month, born.day)
while almost_close_date < now
m_tot = m_tot + 1
almost_close_date = almost_close_date>>(1)
end
m_dif = m_tot - 1

close_date = born >>(m_dif + 12 * y_dif)
d_dif = 0
while close_date < now
d_dif = d_dif + 1
close_date = close_date+(1)
end

puts y_dif, m_dif, d_dif

If this is still too slow,
you could make the day count recursive and split day differences in two (such as in bubble sort :-)

but before you go down that route, check pl/sql first
using the ruby code is less database dependent of course

cheers

Geert
0

Information ArchitectCommented:
I am not aware of the age calculating functionality in Ruby
but you could make the date class do all the calculation work for you
The date class takes care of all the leap year calculations

If you have two date objects (now and born)
this would calculate the year difference

y_dif = now.year - born.year
if Date.new(now.year - year, now.month, now.day) < born
y_dif = y_dif - 1
end

It calculates the difference between the years, checks if subtracting does create a dat prior to the born date
All your leap year calculus is taken into account by the date substraction

I will work on the other two later today
months and days can be calculated in a similar fashion (be it a little bit more complex)
0

CEO/ProgrammerCommented:
require "rubygems"
require "active_support"

It will add a functinality to date-calculations and conversions to Time and so you can
write things like

Time.now - 6.months

and the like I'm sure it does add quite a bit for data calculations also

Regards
Friedrich
0

Information ArchitectCommented:
this calculates the month difference correctly

m_dif = now.month - born.month
if m_dif < 0
m_dif = m_dif + 12
end
if Date.new(born.year, born.month, now.day) < born
m_dif = m_dif - 1
end
0

Information ArchitectCommented:
mmmh, I am not convinced ActiveSupport gives you what you need here
but it has some months_since and years_since methods
you could use them in some sort of jackhammer approach,
counting back days until you hit the birthday
maybe that is better
0

Author Commented:
in the following line:

if Date.new(now.year - year, now.month, now.day) < born

what the 'year" (the second year by itself)  is for?
0

Author Commented:
ok, this seems working:

y_dif = now.year - born.year
if Date.new(now.year, now.month, now.day) < born
y_dif = y_dif - 1
end

+++++++++++

I am doing days difference and I am not sure in this case:

d_dif = now.day - born.day
if d_dif < 0
d_dif = d_dif + 31 # ---> adding 31 would work?
0

Commented:
here's the one i use:

day_diff = Date.today.day - born.day
month_diff = Date.today.month - born.month - (day_diff < 0 ? 1 : 0)
Date.today.year - born.year - (month_diff < 0 ? 1 : 0)
0

Author Commented:
this line doesn't prevent from getting negative number.

day_diff = Date.today.day - born.day
0

Commented:
this part takes care of it

(day_diff < 0 ? 1 : 0)
0

Information ArchitectCommented:
@bobbit31,

> (day_diff < 0 ? 1 : 0)

that part takes care of substracting a month or not, it doesn't make day_diff positive
I am afraid that allthough the ruby code is clean, your approach is a bit naieve
eg.
month_diff = Date.today.month - born.month - (day_diff < 0 ? 1 : 0)
if Date.today.month - born.month = 0 then (day_diff < 0 ? 1 : 0) makes month_diff = -1, where it should be 11 and year should be decremented by 1
this way you end up pretty soon in a code as the one dkim18 started from

@dkim,

you are right, I made a copy and paste error in my year calculation
here is the correct one
y_dif = now.year - born.year
if Date.new(now.year - y_dif, now.month, now.day) < born
y_dif = y_dif - 1
end

there is bug in my month calculus too
I will check that tomorrow
0

Information ArchitectCommented:
here is month corrected (I think)
It works on all the border cases I tested it with

m_dif = now.month - born.month
if m_dif < 1
m_dif = m_dif + 12
end
if Date.new(born.year, born.month, now.day) < born
m_dif = m_dif - 1
end
m_dif = (m_dif == 12 ? 0 : m_dif)

but this is clumsy.
tomorrow with a fresh mind I will clean this up

cheers

Geert
0

Information ArchitectCommented:
Here is how I would deal with day

close_date = born >>(m_dif + 12 * y_dif)

d_dif = 0
while close_date < now
d_dif = d_dif + 1
close_date = close_date+(1)
end

puts d_dif

That is pure jackhammer approach, but it doesn't hurt, it is max. 31 iterations
This is debatable, if you are born on 31-DEC-2006 (you would not be programming this)
you would be nine months old and a number of days.
But 31-DEC-2006 plus nine months is correctly calculated as 30-SEP-2007
and are you then 9 months plus 25 dys or 9 months and 24days
I leave that filosophic note for yourself

I think, that I will use the jackhammer approach to calculate year and month as well,
I would be a lot cleaner, and maybe not considerably slower
More in an hour

Geert
0

Information ArchitectCommented:
life is so much simpler this way

I use the Date library and not the date functions of ActiveSupport, since the latter don't support leapyears etc.

require "date"

now = Date.today
born = Date.new(1967, 5, 8)

m_tot = 0
born_copy = born
while born_copy < now
m_tot = m_tot + 1
born_copy = born_copy>>(1)
end
y_dif,m_dif = (m_tot-1).divmod(12)

close_date = born >>(m_dif + 12 * y_dif)
d_dif = 0
while close_date < now
d_dif = d_dif + 1
close_date = close_date+(1)
end

puts y_dif, m_dif, d_dif

I jackhammer the results, and that is reasonably fast, considering that you will likely not deal with ages over a couple of hundred years
Note that you will have difficulties if you would, since this is based on gregorian calendar

Sorry I did not come up with this easy approach so much earlier
I hope this one works

Geert
0

Commented:
Geert, if you get a chance, could you please show me a failing test case to my age calc?
0

Information ArchitectCommented:
given today is 2007-10-25
born = Date.new(1967, 5, 30)
makes your day difference fail (it gives -5 days where it should say 25 days)
and you can't simply say it is 30-5, because it could as well be 28-5 or 31-5 (- being minus here)

if today were 2007-1-1
and  born=Date.new(2006,12,31)
my method says 0 years, 0 months, 1 day
your method says 0 years, -12 months, -30 days

I hope this helps
cheers

Geert

0

Information ArchitectCommented:
using my method, you should add a test to assure that born date is not later than today
(or you blow up your server if someone wants to be funny)
0

Commented:
right but in the end... we're only talking about years... and the result of mine is still the expected 40.

when i asked for a failing test case, i meant one that reports the actual age wrong.

given today 2007-10-25 and date 1967-05-30:

day_diff = Date.today.day - born.day
=> -5
the actual result doesn't matter, i'm just looking for positive / negative (negative meaning i was born after today's day)

month_diff = Date.today.month - born.month - (day_diff < 0 ? 1 : 0)
=> 10 - 5 - 1
=> 4
again, just looking for a positive or negative

Date.today.year - born.year - (month_diff < 0 ? 1 : 0)
=> 2007 - 1967 - 0
=> 40

0

Information ArchitectCommented:
OK, I see, I think we have a misunderstanding
I know that your year difference calculation is right, that is not my argument

I assumed that dkim18 needed the time difference in year, months and days, given that in his example he calculated month and day difference even after he calculated the year difference
> this line doesn't prevent from getting negative number.
> day_diff = Date.today.day - born.day
I strongly believe my first assumption is right
but that is up to dkim18 to comment upon

Note also that the year difference problem was solved prior to your post
(and stated to be solved by dkim18 in a post 45 minutes before your first post)

so, no offence but I think your answer raised the wrong expectations
(at least with me)

cheers

Geert
0

Commented:
no offence taken... i just had a short and concise solution on hand and decided to post it... the only reason i continued on to ask for a failing test was to see if i personally shouldn't be using the code i posted ;)
0

Author Commented:
thanks for all your efforts. Gertone's method works, but this age calculation might be performed for hundred of people and it is taking forever in that case. Of course for a few people, I get instant result. So Gertone's jackhammer approach is not efficient this case.

I am just wondering since backend DB is oracle, PL/SQL can do this a lot easily?
0

Information ArchitectCommented:
If you really need to do this for hundreds of people...
The jackhammer is only slow for years
so use this for years

y_dif = now.year - born.year
if Date.new(now.year - y_dif, now.month, now.day) < born
y_dif = y_dif - 1
end

and use the jackhammer for months (max 12 iterations)
and use the jackhammer for days (max 30 iterations)

I don't know about the pl/sql
0

Author Commented:
hold on....I found there is dob format something like this:

0087-10-13 00:00:00.0

It looks like someone entered last two digit only and previous program didn't check format properly.
0

Information ArchitectCommented:
try this
puts "0087-10-13 00:00:00.0".gsub(/^(\d{2})(\d{2})(.*)\$/){ |str|
(\$2.to_f > 25 ? "19" : "20" ) + \$2 + \$3
}
0

Author Commented:
ok, that is good enough. I will give you points. Again, thanks for your help on this!
0

Information ArchitectCommented:
welcome
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.