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


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>
bthg::instance().
load(dasmig::dataset::lite);
bthg::instance().load(dasmig::dataset::full);
std::cout << b.date_string() << " — "
<< b.country_code << ", age " << +b.age
<< ", " << b.cohort << '\n';
std::cout << "US: " << us << '\n';
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';
.bio_sex = dasmig::sex::female,
.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());
for (std::uint64_t seed = 100; seed < 103; ++seed)
bthg my_gen;
my_gen.load("path/to/resources/lite");
Birth generator that produces demographically plausible birthdays from country age pyramids.
void load(const std::filesystem::path &dir)
Load data from a resource directory, replacing all data and layers loaded before.
An inclusive range of ages in completed years.
All per-call birth filters and settings.
std::optional< std::string > country_code
ISO 3166-1 alpha-2 code, or random.
bool weighted
Population-weighted (true) or uniform country.
Strong type for a requested birth year.
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:
- Country — select from loaded countries (population-weighted or uniform).
- Sex — male or female, weighted by the country's M:F population ratio (or fixed if specified).
- Age — drawn from the country-specific age pyramid, optionally restricted to a range (or derived from a fixed year).
- Birth year — the year that makes the age exact on the reference date (default 2023-07-01, the date of the UN estimates).
- Month — drawn from latitude-based seasonal weights.
- Day — uniform within the month, with a weekend deficit (weekend days redrawn with probability proportional to the C-section rate).
- Weekday — computed from the final date using
std::chrono.
- Life expectancy remaining —
max(0, LE_at_birth − age).
- 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