Repository: joke2k/faker
Pull request #1426 (2021-04-09 09:00:03)

Extend Pesel To support greater range of dates
### What does this changes

Allow to generate proper pesel for dates from range 1800-2299

### What was wrong

For dates outside 1900-2099 pesel generate incorrect values.

Information about generation is under link https://en.wikipedia.org/wiki/PESEL in section Birthdates

### How this fixes it

modify month date
The PESEL system has been designed to cover five centuries. To distinguish people born in different centuries, numbers are added to the MM field:
for birthdates between 1900 and 1999 – no change to MM field is made (see below)
for other birthdates:
2000–2099 – month field number is increased by 20
2100–2199 – month + 40
2200–2299 – month + 60
1800–1899 – month + 80

Fixes #...


IlfirinPL: @fcurella  Yes, Will write some tests
IlfirinPL: @fcurella  Tests added, documentation for function also update.
IlfirinPL: @fcurella  
I see that formater on windows doesn't like dates old dates  "format %y requires year >= 1900 on Windows"
https://ci.appveyor.com/project/joke2k/faker/builds/38675793/job/kue9e4iel8w4nwyb#L1364
what do you this should be done skip those tests for windows or change way of extraction of values ?
IlfirinPL: Update code with workaround issue with dates below 1900
fcurella: Thank you!

Patch:
diff --git a/faker/providers/person/pl_PL/__init__.py b/faker/providers/person/pl_PL/__init__.py
index e19e51ef..800f76a2 100644
--- a/faker/providers/person/pl_PL/__init__.py
+++ b/faker/providers/person/pl_PL/__init__.py
@@ -712,8 +712,13 @@ class Provider(PersonProvider):
         Polish: Powszechny Elektroniczny System Ewidencji Ludności.
 
         PESEL has 11 digits which identifies just one person.
-        pesel_date: if person was born in 1900-2000, december is 12. If person was born > 2000, we have to add 20 to
-        month, so december is 32.
+        pesel_date: if person was born in
+                1900-1999 - month field number is not modified
+                2000–2099 – month field number is increased by 20
+                2100–2199 – month + 40
+                2200–2299 – month + 60
+                1800–1899 – month + 80
+                outside range 1800-2299 function will raise ValueError
         pesel_sex: last digit identifies person's sex. Even for females, odd for males.
 
         https://en.wikipedia.org/wiki/PESEL
@@ -721,9 +726,22 @@ class Provider(PersonProvider):
         if date_of_birth is None:
             date_of_birth = self.generator.date_of_birth()
 
-        month = date_of_birth.month if date_of_birth.year < 2000 else date_of_birth.month + 20
-        pesel_date = f'{date_of_birth:%y}{month:02d}{date_of_birth:%d}'
+        if 1800 <= date_of_birth.year <= 1899:
+            month = date_of_birth.month + 80
+        elif 1900 <= date_of_birth.year <= 1999:
+            month = date_of_birth.month
+        elif 2000 <= date_of_birth.year <= 2099:
+            month = date_of_birth.month + 20
+        elif 2100 <= date_of_birth.year <= 2199:
+            month = date_of_birth.month + 40
+        elif 2200 <= date_of_birth.year <= 2299:
+            month = date_of_birth.month + 60
+        else:
+            raise ValueError("Date of birth is out of supported range 1800-2299")
+
+        year = date_of_birth.year % 100
 
+        pesel_date = f'{year:02d}{month:02d}{date_of_birth.day:02d}'
         pesel_core = ''.join(map(str, (self.random_digit() for _ in range(3))))
         pesel_sex = self.random_digit()
 


Test patch:
diff --git a/tests/providers/test_person.py b/tests/providers/test_person.py
index e5ff6dc6..59666dcb 100644
--- a/tests/providers/test_person.py
+++ b/tests/providers/test_person.py
@@ -242,9 +242,12 @@ class TestPlPL(unittest.TestCase):
 
     @mock.patch.object(PlPLProvider, 'random_digit')
     def test_pesel_birth_date(self, mock_random_digit):
-        mock_random_digit.side_effect = [3, 5, 8, 8, 7, 9, 9, 3]
+        mock_random_digit.side_effect = [3, 5, 8, 8, 3, 5, 8, 8, 7, 9, 9, 3, 7, 9, 9, 3, 7, 9, 9, 3]
+        assert self.fake.pesel(datetime.date(1899, 12, 31)) == '99923135889'
         assert self.fake.pesel(datetime.date(1999, 12, 31)) == '99123135885'
         assert self.fake.pesel(datetime.date(2000, 1, 1)) == '00210179936'
+        assert self.fake.pesel(datetime.date(2100, 1, 1)) == '00410179932'
+        assert self.fake.pesel(datetime.date(2200, 1, 1)) == '00610179938'
 
     @mock.patch.object(PlPLProvider, 'random_digit')
     def test_pesel_sex_male(self, mock_random_digit):
@@ -258,6 +261,10 @@ class TestPlPL(unittest.TestCase):
         assert self.fake.pesel(datetime.date(2007, 4, 13), 'F') == '07241349161'
         assert self.fake.pesel(datetime.date(1933, 12, 16), 'F') == '33121661744'
 
+    def test_pesel_value_error(self):
+        self.assertRaises(ValueError, self.fake.pesel, datetime.date(2300, 1, 1))
+        self.assertRaises(ValueError, self.fake.pesel, datetime.date(1799, 12, 31))
+
     @mock.patch.object(PlPLProvider, 'random_digit')
     def test_pwz_doctor(self, mock_random_digit):
         mock_random_digit.side_effect = [6, 9, 1, 9, 6, 5, 2, 7, 9, 9, 1, 5]