The Born mixin

This document explains the lino.mixins.human.Born model mixin which defines a database field Born.birth_date and a virtual field Born.age.

A tested document

This is a tested document. The following instructions are used for initialization:

>>> import lino
>>> lino.startup('lino_book.projects.human.settings')
>>> from lino.api.doctest import *
>>> from django.db.models import Q
>>> from lino_book.projects.human.models import Person
>>> from lino.modlib.system.choicelists import Genders
>>> from django.utils import translation

This tutorial uses the same demo database as The Human mixin (see there for more explanations).

The age of a human

For the following examples, we will set the_demo_date in order to have reproducible test cases. At the end of this page we will need to restore the demo date to its original value, which is None:

>>> print(settings.SITE.the_demo_date)
None

We define a utility function for our tests:

>>> def test(birth_date, today):
...    settings.SITE.the_demo_date = i2d(today)
...    p = Person(birth_date=birth_date)
...    p.full_clean()
...    print(p.age)
...    settings.SITE.the_demo_date = None

Here we go.

A person born on April 5, 2002 was 16 years old on June 11, 2018:

>>> test("2002-04-05", 20180611)
16 years

When you get 16 years old tomorrow, then today you are still 15:

>>> test("2002-04-05", 20180404)
15 years

You start being 16 on your birthday.

>>> test("2002-04-05", 20180405)
16 years

For children younger than 5 years Lino adds the number of months:

>>> test("2018-03-01", 20180611)
0 years 3 months

Lino respects the singular forms:

>>> test("2017-05-01", 20180611)
1 year 1 month

Incomplete birth dates

The birth date is an instance of lino.utils.IncompleteDate. Yes, there are people who don't know their exact birth date.

>>> test("2002-05-00", 20180611)
±16 years
>>> test("2002-00-00", 20180611)
±15 years

If you say only your birth day but not the year, then we don't know your age:

>>> test("0000-06-01", 20180611)
unknown

Other languages

The age is translated text:

>>> with translation.override('de'):
...    test("2018-03-01", 20180611)
0 Jahre 3 Monate
>>> with translation.override('de'):
...    test("2017-05-01", 20180611)
1 Jahr 1 Monat
>>> with translation.override('fr'):
...    test("2017-05-01", 20180611)
1 an 1 mois
>>> with translation.override('fr'):
...    test("0000-05-01", 20180611)
inconnu

The leap year bug

In April 2019 Steve reported #2946: Lino was saying 35 years as age of a person whose birth date was 10.04.1984 when today is 04.04.2019. Which is wrong. The person will get 35 only in 6 days. So today she is 34:

>>> test("1984-04-10", 20190404)
34 years

It is now correct since the bug is fixed. We added some more test cases

>>> test("2002-04-05", 20180403)
15 years
>>> test("2002-04-05", 20180402)
15 years
>>> test("2002-04-05", 20180401)
15 years
>>> test("2002-04-05", 20180331)
15 years

The explanation was that each leap year caused one day of difference. In our case the leap years were 2004, 2008 and 2012 and 2016, so Lino starts saying 16 4 days before your birthday: