Calculating the age given DOB

Hello, fellow rubyists.

I have a problem. I'm trying to write a simple program which calculates the age of a person given the person's date of birth in an instance of a Date class. I have no idea what is the best way to do this. I don't feel like using any ugly "hacks" to do it, and I wonder if there is any good (perhaps mathematical) algorithm out there to solve the problem.

--Deniz Dogan

Here is a free Ruby Favicon for all who wish to use it.
Just place it in the top directory of a site (or the appropriate place for a web app) and do the appropriate html.
John Joyce

Deniz Dogan wrote:

Hello, fellow rubyists.

I have a problem. I'm trying to write a simple program which calculates the age of a person given the person's date of birth in an instance of a Date class. I have no idea what is the best way to do this. I don't feel like using any ugly "hacks" to do it, and I wonder if there is any good (perhaps mathematical) algorithm out there to solve the problem.

--Deniz Dogan

(DateTime.now - birthdate) / 365.25

rthompso@jhereg:~$ irb
irb(main):001:0> require 'date'
=> true
irb(main):002:0> bd = Date.new(1966, 1, 21)
=> #<Date: 4878293/2,0,2299161>
irb(main):003:0> today = Date.new(2007,3,14)
=> #<Date: 4908347/2,0,2299161>
irb(main):004:0> age = today.year - bd.year
=> 41

···

On Wed, 2007-03-14 at 23:55 +0900, Deniz Dogan wrote:

Hello, fellow rubyists.

I have a problem. I'm trying to write a simple program which calculates
the age of a person given the person's date of birth in an instance of a
Date class. I have no idea what is the best way to do this. I don't feel
like using any ugly "hacks" to do it, and I wonder if there is any good
(perhaps mathematical) algorithm out there to solve the problem.

--Deniz Dogan

Hello, fellow rubyists.

I have a problem. I'm trying to write a simple program which calculates
the age of a person given the person's date of birth in an instance of a
Date class. I have no idea what is the best way to do this. I don't feel
like using any ugly "hacks" to do it, and I wonder if there is any good
(perhaps mathematical) algorithm out there to solve the problem.

Depends on what you want exactly. If you want to compute the "usual"
age (i.e. I'll say I'm 31 years old, not 31.7426420260096), you might
try this :

d1 = Date.today

=> #<Date: 4908347/2,0,2299161>

d2 = Date.new(1975,6,16)

=> #<Date: 4885159/2,0,2299161>

(d1.year - d2.year) - (d1.yday >= d2.yday ? 0 : 1)

=> 31

d1 = Date.new(2007, 06, 16)

=> #<Date: 4908535/2,0,2299161>

(d1.year - d2.year) - (d1.yday >= d2.yday ? 0 : 1)

=> 32

Fred

···

Le 14 mars à 15:47, Deniz Dogan a écrit :
--
Assignments: telling a variable what it stands for, and/or what value(s)
it should have is coercive and paternalistic: variables should be free
to choose their own names and value-sets from a range of non-sexist,
non-racist options. (Tanuki in the SDM, on politically-correct coding)

Brian Adkins wrote:

(DateTime.now - birthdate) / 365.25

That's not very reliable. There are algorithms that calculate
the number of days since some epoch from a date, and the
reverse, based on Fortran code that was posted in the CACM
sometime around 1970. I have a copy somewhere, but there
must be a modern version already in Ruby. If you can't
find a way, I'll dig out mine.

Just convert both dates to days-since-epoch and subtract.

Clifford.

Brian Adkins wrote:

Deniz Dogan wrote:

Hello, fellow rubyists.

I have a problem. I'm trying to write a simple program which calculates the age of a person given the person's date of birth in an instance of a Date class. I have no idea what is the best way to do this. I don't feel like using any ugly "hacks" to do it, and I wonder if there is any good (perhaps mathematical) algorithm out there to solve the problem.

--Deniz Dogan

(DateTime.now - birthdate) / 365.25

And this would work with Date objects?

Reid Thompson wrote:

···

On Wed, 2007-03-14 at 23:55 +0900, Deniz Dogan wrote:

Hello, fellow rubyists.

I have a problem. I'm trying to write a simple program which calculates the age of a person given the person's date of birth in an instance of a Date class. I have no idea what is the best way to do this. I don't feel like using any ugly "hacks" to do it, and I wonder if there is any good (perhaps mathematical) algorithm out there to solve the problem.

--Deniz Dogan

rthompso@jhereg:~$ irb
irb(main):001:0> require 'date'
=> true
irb(main):002:0> bd = Date.new(1966, 1, 21)
=> #<Date: 4878293/2,0,2299161>
irb(main):003:0> today = Date.new(2007,3,14)
=> #<Date: 4908347/2,0,2299161>
irb(main):004:0> age = today.year - bd.year
=> 41

Consider when today.month < bd.month - you'll have an off-by-one error.

Thats gr8 !
thanks.

···

On 3/14/07, John Joyce <dangerwillrobinsondanger@gmail.com> wrote:

Here is a free Ruby Favicon for all who wish to use it.
Just place it in the top directory of a site (or the appropriate
place for a web app) and do the appropriate html.
John Joyce

--
sur
"is a String object" is a String object
http://expressica.com

F. Senault schrieb:

(d1.year - d2.year) - (d1.yday >= d2.yday ? 0 : 1)

Pardon Fred, using #yday would be short and nice, but this doesn't work reliably if one year is a leap year and the other is not. Try it with

   d1 = Date.new(2007, 3, 1); d2 = Date.new(2004, 3, 1)
   d1 = Date.new(2004, 3, 1); d2 = Date.new(2001, 3, 2)

Regards,
Pit

Deniz Dogan wrote:

Brian Adkins wrote:

Deniz Dogan wrote:

Hello, fellow rubyists.

I have a problem. I'm trying to write a simple program which calculates the age of a person given the person's date of birth in an instance of a Date class. I have no idea what is the best way to do this. I don't feel like using any ugly "hacks" to do it, and I wonder if there is any good (perhaps mathematical) algorithm out there to solve the problem.

--Deniz Dogan

(DateTime.now - birthdate) / 365.25

And this would work with Date objects?

Why don't you give it a try?

Clifford Heath wrote:

Brian Adkins wrote:

(DateTime.now - birthdate) / 365.25

That's not very reliable. There are algorithms that calculate
the number of days since some epoch from a date, and the
reverse, based on Fortran code that was posted in the CACM
sometime around 1970. I have a copy somewhere, but there
must be a modern version already in Ruby. If you can't
find a way, I'll dig out mine.

Just convert both dates to days-since-epoch and subtract.

Clifford.

Do you mind if I ask why you make the statement, "That's not very reliable." ? For what values of birthdate (an instance of Date) would the above expression not be "reliable" ?

Brian Adkins schrieb:

Reid Thompson wrote:

irb(main):001:0> require 'date'
=> true
irb(main):002:0> bd = Date.new(1966, 1, 21)
=> #<Date: 4878293/2,0,2299161>
irb(main):003:0> today = Date.new(2007,3,14)
=> #<Date: 4908347/2,0,2299161>
irb(main):004:0> age = today.year - bd.year
=> 41

Consider when today.month < bd.month - you'll have an off-by-one error.

   age -= 1 if today.month < bd.month || today.month == bd.month && today.day < bd.day

I don't know how people born at February 29th celebrate their birthday in non-leap years. The code above makes them one year older on March 1st.

Regards,
Pit

F. Senault schrieb:

(d1.year - d2.year) - (d1.yday >= d2.yday ? 0 : 1)

Pardon Fred, using #yday would be short and nice, but this doesn't work
reliably if one year is a leap year and the other is not.

Yup, you're perfectly right. The following version seems to work, but
we're steadily losing elegance... :slight_smile:

d1 = Date.new(2007, 3, 1); d2 = Date.new(2004, 3, 1)

=> #<Date: 4906131/2,0,2299161>

(d1.year - d2.year) - (d1.yday >= Date.new(d1.year, d2.month, 1).yday + d2.day - 1 ? 0 : 1)

=> 3

d1 = d1 - 1

=> #<Date: 4908319/2,0,2299161>

(d1.year - d2.year) - (d1.yday >= Date.new(d1.year, d2.month, 1).yday + d2.day - 1 ? 0 : 1)

=> 2

A pity Date.new doesn't handle overflows. I'd like to be able to write
this :

Date.new(2007, 2, 29).to_s

=> '2007-03-01'

Date.new(2007, 3, 0).to_s

=> '2007-02-28'

Fred

···

Le 14 mars 2007 à 20:50, Pit Capitain a écrit :
--
And there shall be no more red roses, but only white, for she has
squeezed the blood of all living things into her cup.
                                                      (Aleister Crowley)

Brian Adkins wrote:

Clifford Heath wrote:

Brian Adkins wrote:

(DateTime.now - birthdate) / 365.25

Do you mind if I ask why you make the statement, "That's not very reliable." ?

I have written genealogy software, and sometimes I want to know
how old someone was on a given date, like when they married.
1900 was not a leap year, as I'm sure you know. Neither was
1800 or 1700, but 1600 was. Does that make more sense now?

If I write a "library function" like this, I like to be a stickler,
because it's usually myself that gets tripped up.

I think we can honestly assume that if you are born on leap day, you become highly tolerant of systems that don't even accept leap day birthdays and probably write Feb 28 or Mar 1 consistently by habit.

···

On Mar 15, 2007, at 2:14 AM, Pit Capitain wrote:

Brian Adkins schrieb:

Reid Thompson wrote:

irb(main):001:0> require 'date'
=> true
irb(main):002:0> bd = Date.new(1966, 1, 21)
=> #<Date: 4878293/2,0,2299161>
irb(main):003:0> today = Date.new(2007,3,14)
=> #<Date: 4908347/2,0,2299161>
irb(main):004:0> age = today.year - bd.year
=> 41

Consider when today.month < bd.month - you'll have an off-by-one error.

  age -= 1 if today.month < bd.month || today.month == bd.month && today.day < bd.day

I don't know how people born at February 29th celebrate their birthday in non-leap years. The code above makes them one year older on March 1st.

Regards,
Pit

Hi! I had this idea, hope it helps:

class Date
  def elapsedYearsAndDays(rangeDate)
    if self > rangeDate
      startDate = rangeDate.clone #clone the values so they are not
changed unintentionally
      endDate = self.clone
    else
      startDate = self.clone
      endDate = rangeDate.clone
    end
    magicDay = (startDate.month == 2) && (startDate.day == 29) #This
is the real problem: Febraury 29th!
    startDate += 1 if !endDate.leap? && magicDay
    elapsedYears = endDate.year - startDate.year
    previousStartDate = Date.new(endDate.year, startDate.month,
startDate.day)
    if endDate < previousStartDate
      elapsedYears -= 1
      previousStartDate = Date.new(endDate.year - 1, startDate.month,
startDate.day)
      previousStartDate -= 1 if previousStartDate.leap? && magicDay
    end
    elapsedDays = endDate - previousStartDate
    return elapsedYears, elapsedDays
  end
end

elapsedYears, elapsedDays =
Date.today.elapsedYearsAndDays(Date.new(1963, 11, 22))
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ""
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}"

elapsedYears, elapsedDays = Date.new(1963, 11,
22).elapsedYearsAndDays(Date.new(1963, 11, 22))
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ""
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}"

elapsedYears, elapsedDays = Date.new(2007, 3,
1).elapsedYearsAndDays(Date.new(2004, 3, 1))
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ""
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}"

elapsedYears, elapsedDays = Date.new(2004, 3,
1).elapsedYearsAndDays(Date.new(2001, 3, 2))
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ""
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}"

elapsedYears, elapsedDays = Date.new(2004, 2,
29).elapsedYearsAndDays(Date.new(2001, 3, 1))
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ""
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}"

elapsedYears, elapsedDays = Date.new(2004, 3,
1).elapsedYearsAndDays(Date.new(2001, 3, 1))
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ""
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}"

elapsedYears, elapsedDays = Date.new(2004, 2,
29).elapsedYearsAndDays(Date.new(2009, 3, 1))
daysMessage = (elapsedDays > 0) ? (" and #{elapsedDays} day(s)") : ""
puts "Elapsed time: #{elapsedYears} year(s)#{daysMessage}"

···

--
Posted via http://www.ruby-forum.com/.

Clifford Heath wrote:

Brian Adkins wrote:

Clifford Heath wrote:

Brian Adkins wrote:

(DateTime.now - birthdate) / 365.25

Do you mind if I ask why you make the statement, "That's not very reliable." ?

I have written genealogy software, and sometimes I want to know
how old someone was on a given date, like when they married.
1900 was not a leap year, as I'm sure you know. Neither was
1800 or 1700, but 1600 was. Does that make more sense now?

If I write a "library function" like this, I like to be a stickler,
because it's usually myself that gets tripped up.

Gotcha. I saw "simple program" and was thinking more in terms of approximate real values vs. discrete values (e.g. gaining a year of age in an instant) which is why I didn't throw in a round. My guess is that the OP probably wants the discrete value though, so the other part of the thread should do the trick.

I think that this does the right thing:

rick@frodo:/public/rubyscripts$ cat datemath.rb
#!/usr/math/bin/ruby

require 'date'
class Date

  # return the number of days since the beginning of the year
  def years_since(date)
    # The parens in the expression below aren't strictly necessary, but
    # I think it makes what's going on a little bit clearer.
    first, last = *(self >= date ? [date, self] : [self, date])
    (self <=> date) * ((last.year - first.year) - (first.yday >
last.yday ? 1 : 0))
  end
end

def tryit(d1,d2)
  puts "There are #{d1.years_since(d2)} years between #{d2} and #{d1}"
end

tryit(Date.new(2007,3,15), Date.new(2000,3,14))
tryit(Date.new(2000,3,14), Date.new(2007,3,15))
tryit(Date.new(2007,3,15), Date.new(2000,3,15))
tryit(Date.new(2007,3,15), Date.new(2000,3,16))
tryit(Date.new(2000,3,16), Date.new(2007,3,15))

tryit(Date.new(2007,2,27), Date.new(2000,2,29))
tryit(Date.new(2000,2,29), Date.new(2000,2,27))
tryit(Date.new(2007,2,28), Date.new(2000,2,29))
tryit(Date.new(2000,2,29), Date.new(2007,2,28))
tryit(Date.new(2000,2,29), Date.new(2007,3,1))
tryit(Date.new(2007,3,1), Date.new(2000,2,29))
tryit(Date.new(2007,3,2), Date.new(2000,2,29))
tryit(Date.new(2000,2,29), Date.new(2007,3,2))

rick@frodo:/public/rubyscripts$ ruby datemath.rb
There are 7 years between 2000-03-14 and 2007-03-15
There are -7 years between 2007-03-15 and 2000-03-14
There are 6 years between 2000-03-15 and 2007-03-15
There are 6 years between 2000-03-16 and 2007-03-15
There are -6 years between 2007-03-15 and 2000-03-16
There are 6 years between 2000-02-29 and 2007-02-27
There are 0 years between 2000-02-27 and 2000-02-29
There are 6 years between 2000-02-29 and 2007-02-28
There are -6 years between 2007-02-28 and 2000-02-29
There are -7 years between 2007-03-01 and 2000-02-29
There are 7 years between 2000-02-29 and 2007-03-01
There are 7 years between 2000-02-29 and 2007-03-02
There are -7 years between 2007-03-02 and 2000-02-29

···

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

John Joyce escreveu:

I think we can honestly assume that if you are born on leap day, you become highly tolerant of systems that don't even accept leap day birthdays and probably write Feb 28 or Mar 1 consistently by habit.

In fact a lot of jurisdictions around the world would not _allow_ the Registrar have a person born in a February 29th...