8000 Handle - and + sign correctly in Swedish Personnummer · jhk-odoo/python-stdnum@5441ffa · GitHub
[go: up one dir, main page]

Skip to content

Commit 5441ffa

Browse files
mxaminarthurdejong
authored andcommitted
Handle - and + sign correctly in Swedish Personnummer
For people aged 100 and up, the minus/dash in the personnummer is changed to a plus, on new year's eve the year they turn 100. See Folkbokföringslagen (1991:481), §18. This makes the - or + sign part of the number. Closes arthurdejong#156 Closes arthurdejong#160
1 parent 9c18ac5 commit 5441ffa

File tree

2 files changed

+31
-9
lines changed

2 files changed

+31
-9
lines changed

stdnum/se/personnummer.py

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@
3131
* https://en.wikipedia.org/wiki/Personal_identity_number_(Sweden)
3232
3333
>>> validate('880320-0016')
34-
'8803200016'
34+
'880320-0016'
35+
>>> validate('8803200016')
36+
'880320-0016'
3537
>>> validate('880320-0018')
3638
Traceback (most recent call last):
3739
...
@@ -54,7 +56,10 @@
5456
def compact(number):
5557
"""Convert the number to the minimal representation. This strips the
5658
number of any valid separators and removes surrounding whitespace."""
57-
return clean(number, ' -+:')
59+
number = clean(number, ' :')
60+
if len(number) in (10, 12) and number[-5] not in '-+':
61+
number = '%s-%s' % (number[:-4], number[-4:])
62+
return number
5863

5964

6065
def get_birth_date(number):
@@ -63,13 +68,18 @@ def get_birth_date(number):
6368
Note that it may be 100 years off because the number has only the last
6469
two digits of the year."""
6570
number = compact(number)
66-
if len(number) == 12:
71+
if len(number) == 13:
6772
year = int(number[0:4])
6873
month = int(number[4:6])
6974
day = int(number[6:8])
7075
else:
7176
year = datetime.date.today().year
72-
year = year - (year - int(number[0:2])) % 100
77+
century = year // 100
78+
if int(number[0:2]) > year % 100:
79+
century -= 1
80+
if number[-5] == '+':
81+
century -= 1
82+
year = int('%d%s' % (century, number[0:2]))
7383
month = int(number[2:4])
7484
day = int(number[4:6])
7585
try:
@@ -90,12 +100,15 @@ def get_gender(number):
90100
def validate(number):
91101
"""Check if the number is a valid identity number."""
92102
number = compact(number)
93-
if len(number) not in (10, 12):
103+
if len(number) not in (11, 13):
94104
raise InvalidLength()
95-
if not isdigits(number):
105+
if number[-5] not in '-+':
106+
raise InvalidFormat()
107+
digits = clean(number, '-+')
108+
if not isdigits(digits):
96109
raise InvalidFormat()
97110
get_birth_date(number)
98-
luhn.validate(number[-10:])
111+
luhn.validate(digits[-10:])
99112
return number
100113

101114

@@ -109,5 +122,4 @@ def is_valid(number):
109122

110123
def format(number):
111124
"""Reformat the number to the standard presentation format."""
112-
number = compact(number)
113-
return number[:6] + '-' + number[6:]
125+
return compact(number)

tests/test_se_personnummer.doctest

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ Test for non-digit number.
3232
Traceback (most recent call last):
3333
...
3434
InvalidFormat: ...
35+
>>> personnummer.validate('a' * 11)
36+
Traceback (most recent call last):
37+
...
38+
InvalidFormat: ...
3539

3640

3741
These numbers should be detected as male or female.
@@ -49,6 +53,12 @@ rejected.
4953
datetime.date(1988, 3, 20)
5054
>>> personnummer.get_birth_date('191705120424')
5155
datetime.date(1917, 5, 12)
56+
>>> personnummer.get_birth_date('121212-1212')
57+
datetime.date(2012, 12, 12)
58+
>>> personnummer.get_birth_date('121212+1212')
59+
datetime.date(1912, 12, 12)
60+
>>> personnummer.get_birth_date('400606+5827')
61+
datetime.date(1840, 6, 6)
5262
>>> personnummer.validate('8899200425')
5363
Traceback (most recent call last):
5464
...

0 commit comments

Comments
 (0)
0