How to find difference in years between two dates?

thebjorn BjornSteinarFjeldPettersen at gmail.com
Wed Jul 26 16:26:43 EDT 2006


Roy Smith wrote:
> "thebjorn" <bp.datakortet.no at gmail.com> wrote:
>
> >   def age(born):
> >       now = date.today()
> >       birthday = date(now.year, born.month, born.day)
> >       return now.year - born.year - (birthday > now and 1 or 0)
>
> I don't get that last line.  There's two things in particular that are
> puzzling me.
>
> 1) What does "birthday > now" mean?  It sounds like you haven't been born
> yet.

I'm making a (perhaps tenous) semantic distinction between birthdate,
the date you were born on, and birthday, an annual event that may or
may not have happened yet this year :-)

> 2) I find the "and 1 or 0" part very confusing.  I can't remember all the
> minor rules about operator precedence, but I'm sure this works out to some
> clever hack involving boolean short-circuit evaluation to get around the
> lack of a ternary operator in python.

You're correct :-)  the line was originally:

    return now.year - born.year - (1 if birthday > now else 0)

which gave a nice traceback on the production server that didn't have
2.5 on it :-(  The and/or short-circuit is a fairly well established
(yet divisive) pydiom, and I was going to say something about people
really ought to learn a few simple precedence rules, but then I
realized the parenthesis aren't needed in the above <ehm..>  The
parenthesis are needed in a version someone else mentioned:

    return now.year - born.year - (birthday > now)

but I wouldn't write that, just like I wouldn't write 1 + True..

> If I need to pull out the reference manual to decipher what an expression means,
> it's too complicated.

Nah, that's a little too restrictive I think. I will agree that the
and/or is more cute than functional, at least in this case. Since it
could also throw, how about:

  def yeardiff(a, b):
      y = a.year - b.year
      if (a.month, a.day) < (b.month, b.day): # tuple comparison
          y -= 1
      return y

  def age(born): return yeardiff(date.today(), born)

> if birthday > now:
>    return now.year - born.year - 1
> else:
>    return now.year - born.year

I prefer to hoist the common expression out of the branches so they
don't have an opportunity to get out of sync, but I get your point.

-- bjorn




More information about the Python-list mailing list