polish-validators
Version:
A set of validator functions that check common polish numbers.
96 lines (95 loc) • 4.08 kB
JavaScript
const PESEL_REGEX = /^\d{11}$/;
const PESEL_WEIGHTS = [1, 3, 7, 9, 1, 3, 7, 9, 1, 3];
/**
* Validates a PESEL (Polish national identification number) string.
* This function validates the control number and ensures the birthdate is also valid.
*
* **Note:** This validator isn't perfect. Some invalid numbers might still return true.
* For example, people born before the year 1931 might accidentally swap their birthyear
* and birthday, and the function will still pass. 1st, 5th, and 9th or 2nd, 6th, and
* 10th numbers may also be swapped while still passing. There is nothing that can really
* be done about that, other than validating against a database of PESEL numbers.
*
* @param {string} pesel - The 11-digit PESEL number as a string.
* @returns {boolean} `true` if the PESEL is valid; `false` otherwise.
*/
export function isPeselValid(pesel) {
if (!PESEL_REGEX.test(pesel) || pesel === '0'.repeat(11)) {
return false;
}
const sum = PESEL_WEIGHTS.reduce((acc, weight, index) => {
return acc + parseInt(pesel.charAt(index)) * weight;
}, 0);
const controlNumber = parseInt(pesel.charAt(10));
if ((10 - (sum % 10)) % 10 !== controlNumber) {
return false;
}
const [year, monthIndex, day] = _getDatePartsFromPesel(pesel);
const date = new Date(year, monthIndex, day);
if (date.getFullYear() !== year || date.getMonth() !== monthIndex || date.getDate() !== day) {
return false;
}
return true;
}
function _getDatePartsFromPesel(pesel) {
const yearPart = parseInt(pesel.substring(0, 2), 10);
const monthPart = parseInt(pesel.substring(2, 4), 10);
const dayPart = parseInt(pesel.substring(4, 6), 10);
let fullYear = 1900 + yearPart;
if (monthPart >= 81 && monthPart <= 92) {
fullYear = 1800 + yearPart;
}
else if (monthPart >= 21 && monthPart <= 32) {
fullYear = 2000 + yearPart;
}
else if (monthPart >= 41 && monthPart <= 52) {
fullYear = 2100 + yearPart;
}
else if (monthPart >= 61 && monthPart <= 72) {
fullYear = 2200 + yearPart;
}
const adjustedMonth = monthPart % 20 || monthPart;
return [fullYear, adjustedMonth - 1, dayPart];
}
/**
* Validates a PESEL (Polish national identification number) string.
* This function validates the control number and ensures the birthdate is also valid.
*
* **Note:** This validator isn't perfect. Some invalid numbers might still return true.
* For example, people born before the year 1931 might accidentally swap their birthyear
* and birthday, and the function will still pass. 1st, 5th, and 9th or 2nd, 6th, and
* 10th numbers may also be swapped while still passing. There is nothing that can really
* be done about that, other than validating against a database of PESEL numbers.
*
* @param {string} pesel - The 11-digit PESEL number as a string.
* @returns {boolean} `true` if the PESEL is invalid; `false` otherwise.
*/
export const isPeselInvalid = (pesel) => !isPeselValid(pesel);
/**
* Extracts the birthdate from a valid PESEL number.
* @param pesel - The 11-digit PESEL number as a string.
* @returns {Date | null} The birthdate as a Date object, or null if PESEL is invalid.
*/
export function getBirthdateFromPesel(pesel) {
if (!isPeselValid(pesel)) {
return null;
}
const [year, monthIndex, day] = _getDatePartsFromPesel(pesel);
return new Date(year, monthIndex, day);
}
export const PeselSex = {
Male: 'male',
Female: 'female',
};
/**
* Extracts the sex from a valid PESEL number.
* @param pesel - The 11-digit PESEL number as a string.
* @returns {PeselSex | null} 'male' if the PESEL belongs to a male, 'female' if it belongs to a female, null if PESEL is invalid.
*/
export function extractSexFromPesel(pesel) {
if (!isPeselValid(pesel)) {
return null;
}
const sexDigit = parseInt(pesel.charAt(9), 10);
return sexDigit % 2 === 0 ? PeselSex.Female : PeselSex.Male;
}