egn

April 16, 2026 · View on GitHub

PyPI package Build Status Documentation Status Coverage

A Python library and command-line tool for validating, parsing and generating the Bulgarian Unified Civil Number (ЕГН / EGN — Единен граждански номер).

Библиотека и команден ред на Python за проверка, анализ и генериране на български Единни граждански номера (ЕГН).


Table of contents / Съдържание


What is an EGN? / Какво е ЕГН?

English. The EGN (Unified Civil Number) is a 10-digit identifier assigned to every Bulgarian citizen and to every foreign resident. It encodes:

PositionsMeaning
1–2Year of birth (last two digits)
3–4Month of birth, with a century offset: +20 for births in the 1800s, +40 for births after 2000
5–6Day of birth
7–9Regional code (0 – 999), assigned by the civil registry and reflecting the place of registration
9The last digit of the regional code also encodes the sex: even = male, odd = female
10Check digit (mod-11 / mod-10 weighted checksum)

Български. ЕГН-то е 10-цифрен идентификатор, съдържащ датата на раждане, район на регистрация, пол и контролна цифра. Месецът е кодиран с добавени +20 за рождени през XIX век и +40 за рождени след 2000 г. Полът се определя от последната цифра на кода на областта: четна → мъж, нечетна → жена.

Note / Забележка. Dates between 1 April 1916 and 13 April 1916 do not exist — Bulgaria adopted the Gregorian calendar by skipping those 13 days. EGNs carrying such dates are considered invalid by this library.


Installation / Инсталация

pip install egn

Supported Python: 3.6+ (the library uses f-strings).


Python API

import egn

validate(egn)

Return True if egn is a valid EGN, False otherwise. Accepts either a str or an int (ints are zero-padded to 10 digits).

Връща True, ако ЕГН-то е валидно.

>>> egn.validate('0021010899')
True
>>> egn.validate(21010899)        # int, will be zero-padded
True
>>> egn.validate('1234567890')
False

parse(egn)

Return a dict describing the EGN. Raises Exception('Invalid EGN') if the input is invalid.

Връща речник с данните, извлечени от ЕГН-то.

>>> egn.parse('1111136273')
{
    'year': 1911,
    'month': 11,
    'day': 13,
    'datetime': datetime.datetime(1911, 11, 13, 0, 0),
    'region_bg': 'София',
    'region_en': 'Sofia',
    'region_iso': 'BG-22',
    'gender': 'Female',
    'egn': '1111136273',
}

get_date(egn)

Return just the date portion of an EGN (decoded year, month, day and a datetime). Returns False for malformed input.

>>> egn.get_date('9941011142')
{'year': 2099, 'month': 1, 'day': 1, 'datetime': datetime.datetime(2099, 1, 1, 0, 0)}

generate(date_from, date_to, gender, region, limit)

Deterministically enumerate valid EGNs matching the given constraints. All parameters are optional and can be mixed freely.

Генерира всички валидни ЕГН-та, които отговарят на зададените филтри. Всички параметри са по избор и могат да се комбинират.

ParameterTypeDefaultMeaning
date_fromstr (YYYY-MM-DD)'1800-01-01'Earliest date of birth to enumerate.
date_tostr (YYYY-MM-DD)todayLatest date of birth to enumerate.
gender'm' / 'male' / 'f'/ 'female'NoneFilter by sex. None returns both.
regionstrNoneRegion name in Latin, Cyrillic or ISO 3166-2 (e.g. 'Sofia', 'София', 'BG-22'). None returns every region.
limitint / None10Maximum number of EGNs to return. Pass None to enumerate every combination.

Examples:

# All EGNs for men born in Sofia on 2020-10-15.
egn.generate(region='Sofia', gender='m',
             date_from='2020-10-15', date_to='2020-10-15',
             limit=None)
# -> 49 EGNs (one per even region code in 624-721)

# All female EGNs in Burgas across January 2020.
egn.generate(region='Burgas', gender='f',
             date_from='2020-01-01', date_to='2020-01-31',
             limit=None)

# Every EGN for a single day regardless of region or gender.
egn.generate(date_from='1999-12-31', date_to='1999-12-31', limit=None)
# -> 1000 EGNs (one per region code 000-999)

# Using Cyrillic or ISO region names.
egn.generate(region='Пловдив', limit=5)
egn.generate(region='BG-16',   limit=5)

How partial inputs compose:

date_from/date_togenderregionlimitResult
date rangeanyanyNFirst N EGNs in the range, all regions, both sexes
single day'm'anyNoneEvery male EGN born that day, across all regions
date rangeany'Varna'NoneEvery EGN born in Varna during the range
date range'f''BG-22'NoneEvery female EGN born in Sofia in the range

generate_random(gender, region, limit)

Return limit random valid EGNs. Each EGN has a uniformly random date between 1800-01-01 and yesterday and a uniformly random region (or the one you specified).

Генерира произволни ЕГН-та.

>>> egn.generate_random(limit=3, region='Varna', gender='f')
['8841020217', '2643026019', '5424077115']

Command-line interface / Команден ред

After installation the egn command is available:

# Validate
$ egn -v 0021010899
0021010899 is valid!

# Parse (prints JSON)
$ egn -p 9941011142
{"year": 2099, "month": 1, "day": 1, "region_bg": "Варна", ...}

# Generate with full filter set
$ egn -g --from 2020-10-15 --to 2020-10-15 --region Sofia --gender m
# -> prints 49 EGNs, one per line

# Generate — omit --limit to enumerate every combination
$ egn -g --from 2020-01-01 --to 2020-01-01 --region Pernik
# -> prints all 18 EGNs for that day and region

# Generate with a cap
$ egn -g --from 2020-01-01 --to 2020-12-31 --region Burgas --limit 100

# Random EGNs
$ egn -r --limit 5
$ egn -r --region Пловдив --gender f --limit 3

Flags:

FlagPurpose
-v EGNValidate a single EGN.
-p EGNParse a single EGN and print JSON.
-gGenerate EGNs matching the given filters.
-rGenerate random EGNs.
-l N / --limit NCap the number of results. Omit with -g to enumerate every combination.
--gender m/fFilter by sex.
--region NAMELatin, Cyrillic, or ISO 3166-2 region name.
--from DATEISO date YYYY-MM-DD. Default 1800-01-01.
--to DATEISO date YYYY-MM-DD. Default: today.

Regions / Области

The regional code in positions 7–9 of the EGN maps to one of 29 administrative regions. The library ships with the full table, keyed by ISO 3166-2 code, Bulgarian name, and English transliteration.

Библиотеката съдържа пълната таблица на 29-те области, като търсенето работи с латиница, кирилица или ISO 3166-2 код.

ISOEnglishБългарскиCode range
BG-01BlagoevgradБлагоевград000–043
BG-02BurgasБургас044–093
BG-03VarnaВарна094–139
BG-04Veliko TurnovoВелико Търново140–169
BG-05VidinВидин170–183
BG-06VratzaВраца184–217
BG-07GabrovoГаброво218–233
BG-08DobrichДобрич790–821
BG-09KurdzhaliКърджали234–281
BG-10KyustendilКюстендил282–301
BG-11LovechЛовеч302–319
BG-12MontanaМонтана320–341
BG-13PazardzhikПазарджик342–377
BG-14PernikПерник378–395
BG-15PlevenПлевен396–435
BG-16PlovdivПловдив436–501
BG-17RazgradРазград502–527
BG-18RuseРусе528–555
BG-19SilistraСилистра556–575
BG-20SlivenСливен576–601
BG-21SmolyanСмолян602–623
BG-22SofiaСофия624–721
BG-23Sofia (county)София (окръг)722–751
BG-24Stara ZagoraСтара Загора752–789
BG-25TargovishteТърговище822–843
BG-26HaskovoХасково844–871
BG-27ShumenШумен872–903
BG-28YambolЯмбол904–925
BG-XXOtherДруг926–999

Algorithm / Алгоритъм

The checksum in position 10 is computed from the first 9 digits using the weights (2, 4, 8, 5, 10, 9, 7, 3, 6):

checksum = (sum(weight_i * digit_i for i in 1..9) mod 11) mod 10

If that value equals the 10th digit, the EGN is well-formed. The library additionally verifies that positions 1–6 decode to a real calendar date, that the date is not inside the 1–13 April 1916 Gregorian gap, and that the regional code is in range.

Reference: http://www.grao.bg/esgraon.html#section2


Development / Разработка

git clone https://github.com/miglen/egn.git
cd egn
python3 -m venv .venv && source .venv/bin/activate
pip install -e . pytest
pytest test/

Contributions welcome. Please include a test case with any bug fix or new feature.

Приноси са добре дошли. Моля, добавяйте тест за всяка корекция или нова възможност.


License / Лиценз

GNU General Public License v3.0 — see LICENSE.