Age calculation in the model

Hi!

I’m at my wits end with this problem and hopefully someone can help
me.

I have code to calculate age based on date of death - date of birth.
I want the age to calculate down to the minute, which it is. However,
I have to account for all age units: minutes, hours, days, months, or
years. My problem is that I need to have if statements set up for
every scenario, but I want to exit the model when the correct age unit
has been established. Rails is continuting to evaluate the other if
statements, even when I’m checking for nil, and ends up returning 0 in
the case of an age unit less than a year. I have tried assembling the
if statements in a number of ways, including using a “return”
statement when the correct age unit has been calculated. This works,
but the model returns an error if there is more than one return
statement in existence. I just don’t know what else to try!! Any
help would be GREATLY appreciated!!

Here’s my code:

def age
dod = self.precase.report.dod

@age ||= begin
  a = read_attribute(:age)
      dateofbirth = read_attribute(:dob)
      if not dateofbirth.nil?
        if not dod.nil?

          seconds = dod.to_time - dateofbirth.to_time
          minutes = seconds / 60
          m = minutes.to_i


        if m.between?(1, 59)
           m
        end

        hours = minutes / 60
        h = hours.to_i

        if not h.nil?
          if h.between?(1, 23)
             h
          end
        end

        days = h / 24
        d = days.to_i

        if not d.nil?
          if d.between?(1, 30)
           d
          end
        end

        months = days / 30
        mths = months.to_i

       if not mths.nil?
        if mths.between?(1, 11)
           mths
        else
           years = dod.year - dob.year-(dob.to_time.change(:year

=> dod.year) > dod ? 1 : 0)
end
end
end
end
end
end

On Feb 2, 1:13 pm, “Ali” [email protected] wrote:

has been established. Rails is continuting to evaluate the other if
def age
m = minutes.to_i
h
end
end
end
end
end
end
end

Couple of things here…

  1. use the ‘ruby-units’ gem to help with the unit conversions

  2. use a ‘case’

require ‘rubygems’
require ‘ruby-units’
require ‘date’

dob = DateTime.new(1969,4,24,10,30,0)
dod = DateTime.new(2068,1,31,11,30,0)

age = dod.unit - dob.unit

@age = age.to case
when age < ‘1 min’.unit : ‘sec’
when age < ‘1 hr’.unit : ‘min’
when age < ‘1 day’.unit : ‘hour’
when age < ‘1 week’.unit : ‘day’
when age < ‘1 year’.unit : ‘week’
when age < ‘10 years’.unit : ‘year’
when age < ‘100 years’.unit : ‘decade’
else
‘century’
end

puts “#{‘%0.2f’ % @age}”

#=> 9.88 decade

Note that ruby-units doesn’t define a ‘month’ unit (because it isn’t
fixed). But you can define one that is 30 days long if you like.
You also want to use the format string in the to_s or you get this…

15900642/15778463 century

Because DateTime likes to make things Rational.

If you want the output to match the units of another compatible unit
just pass it in the ‘to’ call

age = ‘9.88 decade’.unit
another_age = ‘77 year’.unit

age.to(another_age) #=> 98.8 year

As you can also see, if you have a string that defines your target
unit, you just need to do…

age.to(target_unit)

_Kevin

On Feb 2, 2:32 pm, “_Kevin” [email protected] wrote:

I want the age to calculate down to the minute, which it is. However,
help would be GREATLY appreciated!!
if not dod.nil?
h = hours.to_i
if not d.nil?
mths
Couple of things here…
dod = DateTime.new(2068,1,31,11,30,0)
when age < ‘100 years’.unit : ‘decade’
You also want to use the format string in the to_s or you get this…

age.to(another_age) #=> 98.8 year

As you can also see, if you have a string that defines your target
unit, you just need to do…

age.to(target_unit)

_Kevin

Almost forgot… ruby-units also supports ranges, so this works too

@age = age.to case age
when ‘0 sec’.unit …‘1 min’.unit : ‘sec’
when ‘1 min’.unit … ‘1 hr’.unit : ‘min’
when ‘1 hr’.unit … ‘1 day’.unit : ‘hour’
when ‘1 day’.unit … ‘1 week’.unit : ‘day’
when ‘1 week’.unit … ‘1 year’.unit : ‘week’
when ‘1 year’.unit … ‘10 years’.unit : ‘year’
when ‘10 years’.unit … ‘100 years’.unit : ‘decade’
else
‘century’
end

_Kevin

I used the following for number of seconds in each date part:

year = 365.25 * 60 * 60 * 24 = 31557600
month = year / 12 = 2629800
day = 60 * 60 * 24 = 86400
hour = 60 * 60 = 3600
minute = 60
second = 1

This function, then, returns a hash of the date parts:

def age_parts(in_seconds)
parts = Hash.new
factors = [[‘years’, 31557600],[‘months’, 2629800],[‘days’,
86400],[‘hours’, 3600],[‘minutes’,60],[‘seconds’,1]]
age = factors.collect do |unit, factor|
value, in_seconds = in_seconds.divmod(factor)
parts[unit] = value
end
parts
end

irb(main):187:0> parts = age_parts(1176095625)
=> {“days”=>6, “seconds”=>45, “minutes”=>43, “years”=>37, “hours”=>15,
“months”=>3}
irb(main):188:0> parts[‘years’]
=> 37
irb(main):189:0> parts[‘months’]
=> 3
irb(main):190:0> parts[‘days’]
=> 6
irb(main):191:0> parts[‘hours’]
=> 15
irb(main):192:0> parts[‘minutes’]
=> 43
irb(main):193:0> parts[‘seconds’]
=> 45