Documentation
Reference notes
How PESEL validation works
PESEL Structure
A PESEL number is an 11-digit identifier with format: YYMMDDZZZGX
- YYMMDD: Date of birth (with century offsets encoded in the month).
- ZZZG: Individual sequence number and gender.
- G: Gender digit (even/0 = female, odd = male).
- X: Checksum control digit.
Century Offsets Table
To handle different birth centuries, the month digits are modified:
- 1800 – 1899: Month + 80
- 1900 – 1999: Month + 0
- 2000 – 2099: Month + 20
- 2100 – 2199: Month + 40
- 2200 – 2299: Month + 60
Checksum Verification Formula
The checksum control digit is verified using weighted multiplication: $$\text{Sum} = (1\cdot d_1 + 3\cdot d_2 + 7\cdot d_3 + 9\cdot d_4 + 1\cdot d_5 + 3\cdot d_6 + 7\cdot d_7 + 9\cdot d_8 + 1\cdot d_9 + 3\cdot d_{10}) \pmod{10}$$ $$\text{Control Digit} = (10 - \text{Sum}) \pmod{10}$$
PESEL examples
Valid PESEL Numbers
- 92082612336: Valid male PESEL born on August 26, 1992.
- 92082612343: Valid female PESEL born on August 26, 1992.
Invalid PESEL Numbers
- 92082612335: Invalid checksum digit (expected 6, got 5).
- 920826: Too short (must be exactly 11 digits).
- 920826abcde: Contains non-numeric characters.
PESEL FAQ & Pitfalls
Common Integration Mistakes
- Treating Month as 1-12: Developers often forget the century offset (e.g. +20 for years 2000+). A birth date in 2005-08-12 is encoded as month 28 (
052812...), which causes parsing errors if not mapped properly. - Saving as Integer: PESEL numbers can have leading zeros (e.g. born in 2000-2009). Saving them as raw integers truncates the leading digit, corrupting the length and validation. Store as
VARCHAR(11). - Ignoring the Checksum: Many legacy systems check the 11-digit length only, bypassing checksum validation, allowing typo errors.
PESEL references
Official Regulations & References
- Ministry of Digital Affairs (Poland): Official definition of the PESEL registry.
- Act of 24 September 2010 on Population Registration: Legal base for Polish identifiers and sequence allocations.
- PESEL Registry Specifications: Gov.pl portal guidelines for developers integrating domestic systems.
PESEL developer examples
JavaScript Implementation
function validatePESEL(pesel) {
if (!/^\d{11}$/.test(pesel)) return false;
const weights = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
let sum = 0;
for (let i = 0; i < 10; i++) {
sum += parseInt(pesel[i]) * weights[i];
}
const checksum = (10 - (sum % 10)) % 10;
return checksum === parseInt(pesel[10]);
}
Python Implementation
def validate_pesel(pesel: str) -> bool:
if not pesel.isdigit() or len(pesel) != 11:
return False
weights = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3]
digits = [int(d) for d in pesel]
sum_val = sum(d * w for d, w in zip(digits[:10], weights))
checksum = (10 - (sum_val % 10)) % 10
return checksum == digits[10]
Java Implementation
public class PeselValidator {
public static boolean validate(String pesel) {
if (pesel == null || !pesel.matches("\\d{11}")) {
return false;
}
int[] weights = {1, 3, 7, 9, 1, 3, 7, 9, 1, 3};
int sum = 0;
for (int i = 0; i < 10; i++) {
sum += Character.getNumericValue(pesel.charAt(i)) * weights[i];
}
int checksum = (10 - (sum % 10)) % 10;
return checksum == Character.getNumericValue(pesel.charAt(10));
}
}