-
Notifications
You must be signed in to change notification settings - Fork 2
/
fodselsnummer.py
148 lines (133 loc) · 4.62 KB
/
fodselsnummer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
"""Functions for validation and generation of Norwegian fodselsnumbers"""
import re
from datetime import date, datetime, timedelta as td
FNR_REGEX = re.compile(r'\d{11}')
class FodselsnummerException(Exception):
pass
class InvalidControlDigitException(FodselsnummerException):
pass
def check_fnr(fnr, d_numbers=True):
"""
Check if a number is a valid fodselsnumber.
Only checks the control digits, does not check if the
individual numbers are used in the relevant year
Args:
fnr: A string containing the fodselsnummer to check
d_numbers: True (the default) if d-numbers should be accepted
Returns:
True if it is a valid fodselsnummer, False otherwise.
"""
if not FNR_REGEX.match(fnr):
return False
try:
datetime.strptime(fnr[0:6], '%d%m%y')
except ValueError:
if d_numbers:
dnrdatestring = str(int(fnr[0])-4) + fnr[1:6]
try:
datetime.strptime(dnrdatestring, '%d%m%y')
except ValueError:
return False
else:
return False
try:
generatedfnr = _generate_control_digits(fnr[0:9])
except InvalidControlDigitException:
return False
return bool(fnr == generatedfnr)
def generate_fnr_for_year(year, d_numbers):
"""
Generates all the possible fodselsnumbers for a year.
Args:
year: The year to generate fodselsnummers for (integer)
d_numbers: True if you want d-numbers as well, False otherwise.
Returns:
A list with all the possible fodselsnummers for that year.
"""
allfnrs = []
startdate = date(year, 1, 1)
enddate = date(year, 12, 31)
delta = enddate - startdate
for i in range(delta.days + 1):
allfnrs += generate_fnr_for_day(startdate + td(days=i), d_numbers)
return allfnrs
def generate_fnr_for_day(day, d_numbers):
"""
Generates all the possible fodselsnumbers for a day.
Args:
day: The day to generate fodslesnummers for (datetime)
d_numbers: True if you want d-numbers as well, False otherwise.
Returns:
A list with all the possible fodselsnummers for that day.
"""
thisdaysfnr = []
stupid1900s = False
datestring = day.strftime('%d%m%y')
if d_numbers:
dnrdatestring = str(int(datestring[0])+4) + datestring[1:]
# ref:
# http://www.kith.no/upload/5588/KITH1001-2010_Identifikatorer-for-personer_v1.pdf
# Does not account for the 1800s, since this is for living persons
# (this means that the 1800s list will be a little longer than necessary)
if 1900 <= day.year <= 1999:
individualmin = 000
individualmax = 499
if 1940 <= day.year <= 1999:
stupid1900s = True
else:
individualmin = 500
individualmax = 999
for x in range(individualmin, individualmax+1):
individualnr = str(x).zfill(3)
try:
thisdaysfnr.append(_generate_control_digits(datestring + individualnr))
except InvalidControlDigitException:
pass
if d_numbers:
try:
thisdaysfnr.append(_generate_control_digits(dnrdatestring + individualnr))
except InvalidControlDigitException:
pass
# Bonus round because of the stupid 1900s
if stupid1900s:
for x in range(900, 1000):
individual_nr = str(x).zfill(3)
try:
thisdaysfnr.append(_generate_control_digits(datestring + individualnr))
except InvalidControlDigitException:
pass
if d_numbers:
try:
thisdaysfnr.append(_generate_control_digits(dnrdatestring + individualnr))
except InvalidControlDigitException:
pass
return thisdaysfnr
def _generate_control_digits(numbersofar):
"""Generates the magic control digits in a fodselsnumber"""
staticnumbers1 = [3, 7, 6, 1, 8, 9, 4, 5, 2, 1]
staticnumbers2 = [5, 4, 3, 2, 7, 6, 5, 4, 3, 2, 1]
sum1 = 0
for x in range(0, 9):
sum1 += int(numbersofar[x]) * staticnumbers1[x]
rest = sum1 % 11
if rest == 0:
control1 = 0
else:
if 11-rest != 10:
control1 = 11-rest
else:
raise InvalidControlDigitException
numbersofar += str(control1)
sum2 = 0
for x in range(0, 10):
sum2 += int(numbersofar[x]) * staticnumbers2[x]
rest = sum2 % 11
if rest == 0:
control2 = 0
else:
if 11-rest != 10:
control2 = 11-rest
else:
raise InvalidControlDigitException
numbersofar += str(control2)
return numbersofar