Birth Generator 3.2.2
Procedural birth date generation for C++23
Loading...
Searching...
No Matches
Birth Generator for C++

‍Requires C++23 (e.g., -std=c++23 for GCC/Clang, /std:c++latest for MSVC).

Birth Generator for C++

GitHub license CI GitHub Releases C++23 Header-only Documentation

API Reference · Usage Guide · Data and Method · Releases

Demographically plausible birthdays and ages, from each country's age pyramid, birth seasonality and weekday patterns.

Features

  • Demographically Plausible Birthdays. Generates random birthdays using a multi-axis pipeline: country-specific age pyramids, monthly birth seasonality, and weekday deficit from C-section rates.
  • Population-Weighted Country Selection. Countries are selected with probability proportional to their population, mirroring real-world demographics — a birth from India or China is far more likely than one from Iceland.
  • Rich Birth Data. Every generated birth includes: ISO date (YYYY-MM-DD), year, month, day, age, biological sex, weekday, life expectancy remaining, generational cohort label, and country code.
  • UN WPP 2024 Data. Age pyramids and life expectancy sourced from the United Nations World Population Prospects 2024 revision via the PPgp/wpp2024 R package.
  • Monthly Seasonality. Latitude-based sinusoidal model — Northern Hemisphere peaks in September, Southern Hemisphere peaks in March.
  • Weekday Deficit. Weekend births are less probable in countries with high C-section / scheduled delivery rates, reflecting real-world hospital scheduling patterns.
  • Uniform Selection. Use birth_request{.weighted = false} for equal-probability country selection.
  • Per-Call Requests. Use birth_request with get_birth(request) or get_birth(request, seed) to combine country, sex, year or age filters with per-call weighting and reference date. All generation choices live on the request.
  • Deterministic Seeding. Per-call get_birth(request, seed) for reproducible results, and birth::seed() for replaying a previous generation with the same request. Unseeded requests use ordinary random generation.
  • Batch Generation. Generate thousands of results from one seed, on several threads with the same output for any thread count, optionally unique by a key, and stream them as JSON Lines or CSV (see the usage guide).
  • Identical Everywhere. A seed gives the same birth on every compiler, standard library and CPU (GCC, Clang, MSVC, Emscripten; x86-64 and ARM64), checked by known-answer tests. Ages are relative to a fixed reference date, not the clock.
  • Extensible Data. Load your own TSV layers on top of the shipped data to add, change or remove countries (extend()), checked before they are applied.
  • JSON and Replay. to_json() on every result, and a signature() recording the seed and the data it came from.
  • Compiled-in Data. Define DASMIG_BIRTH_EMBED to build the lite tier into the program, for WebAssembly and other builds without files.
  • Multi-Instance Support. Construct independent bthg instances with their own data and random engine.

Integration

birthgen.hpp is the library released here. Keep core.hpp and the core/ directory (dasmig-core) in the same directory. Add

Birth generator library — procedural birthday generation for C++23.

to the files you want to use it in, and supply the resources folder (or define DASMIG_BIRTH_EMBED).

Usage

#include <iostream>
// For convenience.
using bthg = dasmig::bthg;
// Manually load a specific dataset tier if necessary.
bthg::instance().load(dasmig::dataset::lite); // ~195 sovereign states
// OR
bthg::instance().load(dasmig::dataset::full); // ~235 countries & territories
// Generate a random birth (population-weighted country selection).
auto b = bthg::instance().get_birth(dasmig::birth_request{});
std::cout << b.date_string() << " — "
<< b.country_code << ", age " << +b.age
<< ", " << b.cohort << '\n';
// Generate a birth from a specific country.
auto us = bthg::instance().get_birth(dasmig::birth_request{.country_code = "US"});
std::cout << "US: " << us << '\n'; // implicit string conversion
// Request a specific sex.
auto m = bthg::instance().get_birth(dasmig::birth_request{
.country_code = "BR", .bio_sex = dasmig::sex::male});
// Request a specific birth year.
auto y = bthg::instance().get_birth(dasmig::birth_request{
.country_code = "JP", .year = dasmig::year_t{1990}});
// Request both sex and year.
auto sy = bthg::instance().get_birth(dasmig::birth_request{
.country_code = "DE", .bio_sex = dasmig::sex::female, .year = dasmig::year_t{1985}});
// Request an age range (e.g. adults 18–65).
auto ar = bthg::instance().get_birth(dasmig::birth_request{
.country_code = "US", .ages = dasmig::age_range{18, 65}});
// Access all available fields.
std::cout << "Sex: " << (b.bio_sex == dasmig::sex::male ? "M" : "F") << '\n';
std::cout << "Weekday: " << +b.weekday << " (0=Sun..6=Sat)" << '\n';
std::cout << "LE left: " << b.le_remaining << " years" << '\n';
// Deterministic generation — same request, seed and data produce the same birth.
auto seeded = bthg::instance().get_birth(dasmig::birth_request{}, 42);
// Per-call filters and settings.
.country_code = "US",
.bio_sex = dasmig::sex::female,
.ages = dasmig::age_range{18, 65},
.weighted = false,
.reference_date = std::chrono::year{2040} / std::chrono::January / std::chrono::day{1}};
auto requested = bthg::instance().get_birth(request, 42);
auto requested_replay = bthg::instance().get_birth(request, requested.seed());
// Replay a previous birth using its seed.
auto replay = bthg::instance().get_birth(dasmig::birth_request{}, seeded.seed());
// Deterministic sequences use an explicit seed for every call.
for (std::uint64_t seed = 100; seed < 103; ++seed)
std::cout << bthg::instance().get_birth(dasmig::birth_request{}, seed) << '\n';
// Switch to uniform random selection (equal probability per country).
auto uniform = bthg::instance().get_birth(dasmig::birth_request{.weighted = false});
// Independent instance — separate data and random engine.
bthg my_gen;
my_gen.load("path/to/resources/lite");
auto c = my_gen.get_birth(dasmig::birth_request{});
Birth generator that produces demographically plausible birthdays from country age pyramids.
Definition birthgen.hpp:190
void load(const std::filesystem::path &dir)
Load data from a resource directory, replacing all data and layers loaded before.
Definition birthgen.hpp:412
An inclusive range of ages in completed years.
Definition birthgen.hpp:52
All per-call birth filters and settings.
Definition birthgen.hpp:63
std::optional< std::string > country_code
ISO 3166-1 alpha-2 code, or random.
Definition birthgen.hpp:69
bool weighted
Population-weighted (true) or uniform country.
Definition birthgen.hpp:76
Strong type for a requested birth year.
Definition birthgen.hpp:42

birth_request{} uses population-weighted selection and birth_request::default_reference_date (2023-07-01). Omit country_code for a random country; set year = dasmig::year_t{1990} for a fixed year instead of ages. Specifying both year and ages throws std::invalid_argument. get_birth(request) draws a seed from the generator's random engine; get_birth(request, seed) does not advance it. Replay requires the same request, seed and loaded data.

The positional/no-argument get_birth overloads and generator-wide weighted() / reference_date() getter/setters and seed() / unseed() controls have been removed. Pass an explicit request on every call, including birth_request{} for defaults; move weighting and reference-date choices onto that request, and pass deterministic seeds as the second argument. Result fields, seeded output and data APIs are unchanged. See Migrating to request-first generation.

For the complete feature guide — fields, seeding, weighting, and more — see the Usage Guide.

Generation Pipeline

Each call to get_birth() runs this pipeline:

  1. Country — select from loaded countries (population-weighted or uniform).
  2. Sex — male or female, weighted by the country's M:F population ratio (or fixed if specified).
  3. Age — drawn from the country-specific age pyramid, optionally restricted to a range (or derived from a fixed year).
  4. Birth year — the year that makes the age exact on the reference date (default 2023-07-01, the date of the UN estimates).
  5. Month — drawn from latitude-based seasonal weights.
  6. Day — uniform within the month, with a weekend deficit (weekend days redrawn with probability proportional to the C-section rate).
  7. Weekday — computed from the final date using std::chrono.
  8. Life expectancy remaining — max(0, LE_at_birth − age).
  9. Cohort label — Greatest Generation through Generation Alpha.

Data

The birth data is sourced from:

Source License Contribution
PPgp/wpp2024 (UN WPP 2024) CC BY 3.0 IGO Age pyramids, life expectancy at birth
REST Countries v3.1 Open Source ISO codes, latitude, independence status
WHO Global Health Observatory Reference C-section rates by country

See LICENSE_DATA.txt for details.

To regenerate datasets:

python scripts/prepare_births.py # generate both tiers
python scripts/prepare_births.py --tier lite # lite only
python scripts/prepare_births.py --tier full # full only

Building

make # example
make test # tests
make bench # benchmarks, results in build/bench.tsv
make test-embed # tests with the lite tier compiled in
make coverage # code coverage
make lint # clang-tidy
make docs # API docs
make embed # regenerate dasmig/birthgen_data.hpp from resources/lite

For targeted checks after make test: ./build/test_runner "[request],[kat]".

Compiler Support

Tested with:

  • Clang 18+ (-std=c++23)
  • GCC 14+ (-std=c++23)
  • MSVC 19.38+ (/std:c++latest)
  • Emscripten 3.1.74

Dependencies

Dependency Version Bundled Purpose
dasmig-core 1.4 Yes (core.hpp, core/) Platform-independent random engine and distributions, data layers, JSON
Catch2 3.x Yes (amalgamated) Unit testing

Related Libraries

Library Description
address-generator Postal addresses with real streets by place
biodata-generator Procedural human physical characteristics
city-generator Weighted city selection by population
country-generator Weighted country selection by population
device-generator Devices, browsers, user agents and IP addresses that fit together
email-generator Email addresses in each country's style
entity-generator ECS-based entity generation
interest-generator Religion, hobbies and favourite media by country, age and sex
name-generator Culturally appropriate full names
nickname-generator Gamer-style nicknames
occupation-generator Employment status, education and occupation by country, age and sex
persona-generator Complete characters composed from the other generators
phone-generator Phone numbers valid in each country's numbering plan
relationship-generator Families around a person: parents, siblings, partners and children
trait-generator Personality traits with conflicts, synergies and Big Five axes
user-generator Complete user records: account, username, email, phone and address

License

This library is released under the MIT License.

MIT License
Copyright (c) 2020-2026 Diego Dasso Migotto