How Lifetime calculates its perspective
Plain-language explanation of the statistical method. The same content, condensed, is shown in the app under "How this is calculated".
The quantity
Lifetime shows remaining life expectancy at the person's current attained age, written e(x) in a life table: the average number of additional years lived by people in the reference population who have already reached exact age x.
It is not "life expectancy at birth minus your age". That shortcut ignores the fact that having reached age x, a person has already survived the mortality risks of every earlier age; e(x) + x is always larger than e(0) for x > 0.
The data
| Publisher | United Nations, Department of Economic and Social Affairs, Population Division |
| Dataset | World Population Prospects 2024 — complete (single-year-of-age) life tables, estimates 1950–2023 |
| Files | WPP2024_Life_Table_Complete_Medium_{Both,Male,Female}_1950-2023.csv.gz (SHA-256 in data/VALIDATION_REPORT.md) |
| Column used | ex — expectation of life at exact age x. Directly published; nothing is derived from mx/qx. |
| Reference period | calendar year 2023, the latest estimate year in the release (2024 onward are projections and are not used) |
| Table type | Period life table |
| Geography | 237 countries/areas (LocTypeName == "Country/Area" with an ISO-3166 alpha-3 code). UN regional/income aggregates are excluded. |
| Population categories | total = the UN's published both-sexes combined table; male; female. The combined table is never manufactured by averaging. |
| Ages | 0–99 single years, plus the open-ended 100+ group |
| License | Creative Commons Attribution 3.0 IGO (CC BY 3.0 IGO). Attribution: "© 2024 United Nations, DESA, Population Division. World Population Prospects 2024." Confirm on the WPP site before release (launch check). |
Import and validation are reproducible: python3 data/import_wpp2024.py --download --raw data/raw --out App/Lifetime/Resources/LifeTables. The script filters, validates (complete ages, no duplicates, plausible e(0) and e(100+), all values positive, strictly decreasing e(x) from age 5, combined table within the male/female range), writes the compact JSON snapshot bundled with the app, writes reference_rows.json, and records checksums.
Reference rows were additionally cross-checked against the raw CSV with an independent awk pass (e.g. Austria, total, age 40: 42.8811; Nigeria, total, age 0: 54.4623 and age 1: 57.5101).
Age handling
- Attained age is computed with calendar arithmetic (
Calendar.dateComponents([.year])) from the birth day and the current day in the user's time zone. Ages are birthday-based: 39 until the day of the 40th birthday. - Leap-day birthdays (29 February) follow Foundation's rule: in non-leap years the birthday counts as reached on 28 February. Tests cover this.
- Between birthdays Lifetime interpolates linearly between e(x) and e(x+1) by the fraction of the age-year elapsed (days since last birthday ÷ days in this age-year). Within one year of age e(x) is very close to linear, so the interpolation keeps the shown value from jumping by roughly a year on each birthday while staying anchored to published values. The published e(x) at the completed age is also shown, so the interpolation is transparent.
- Recalculated every launch. Nothing is frozen at onboarding; there is no stored "end date" from which time is subtracted.
- Ages 100 and over use the published open-ended 100+ value as-is. The person's age is never clamped, no negative time is ever returned, and the screen explains the open-ended group.
- Future birth dates and completed ages above 130 are rejected as input errors. Onboarding requires the person to be 18 or older.
What the number means — and does not
- It is a population average, not a personal allocation of time. Roughly half of people at that age live longer than e(x), and half do not.
- It is a period estimate: it applies 2023 mortality rates at every future age. It is not a forecast of medical or social change. Cohort estimates are not mixed in.
- It says nothing about the individual's health, habits, or circumstances, and by design nothing the person does in the app changes the figure.
- Changing the country of residence changes the reference population. That is not evidence of any individual causal effect, and the app never frames it that way.
- No confidence interval is shown: the source does not publish one for e(x), and Lifetime will not invent one. A sentence about individual variation replaces a fabricated range.
Unsupported cases
If the dataset fails validation, the country is not in the dataset, or a population table is missing for that country, the engine returns an explicit error and the app shows the non-numeric ("Focus on today") experience with a plain explanation. It never substitutes another country or fabricates a value.
Where the code lives
LifetimeCore/Sources/LifetimeCore/Statistics/—AgeCalculator,LifeExpectancyEngine,LifeTableRepository, dataset models. Deterministic, UI-free, injected clock and calendar.LifetimeCore/Tests/LifetimeCoreTests/— verified reference-row tests against the bundled snapshot; behavioural tests on a clearly labelled synthetic table (never shipped); corrupt-data rejection; leap-day and birthday tests.
Updating the dataset
- When a new WPP release appears, update
FILES,REFERENCE_YEAR,releaseanddatasetIDindata/import_wpp2024.py(rename it accordingly). - Run the script with
--download; it fails loudly on any validation problem. - Copy the new
reference_rows.jsonand snapshot intoLifetimeCore/Tests/LifetimeCoreTests/Fixtures/and runswift test. - Re-read the license page and update
attributionif the wording changed.