diff --git a/README b/README index 563e4eb4..e68ba924 100644 --- a/README +++ b/README @@ -55,6 +55,7 @@ Currently this package supports the following formats: * IMSI (International Mobile Subscriber Identity) * Kennitala (Icelandic personal and organisation identity code) * VSK number (Virðisaukaskattsnúmer, Icelandic VAT number) + * IK (Isikukood, Estonian personal ID) * ISAN (International Standard Audiovisual Number) * ISBN (International Standard Book Number) * ISIL (International Standard Identifier for Libraries) diff --git a/stdnum/ee/ik.py b/stdnum/ee/ik.py new file mode 100644 index 00000000..6633ff2b --- /dev/null +++ b/stdnum/ee/ik.py @@ -0,0 +1,91 @@ +# ik.py - functions for handling Estonian Personal ID numbers (IK) +# coding: utf-8 +# +# Copyright (C) 2012, 2013 Arthur de Jong, 2015 Tomas Karasek +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +# 02110-1301 USA + +""" (Isikukood, Estonian Personcal ID number). + +>>> validate('36805280109') +'36805280109' +>>> validate('36805280108') # incorrect check digit +Traceback (most recent call last): + ... +InvalidChecksum: ... +>>> print get_birth_date('36805280109') +1968-05-28 + +""" + +import stdnum.exceptions +from stdnum.util import clean +import datetime + + +def compact(number): + return number.strip() + + +def get_birth_date(number): + if number[0] in ['1','2']: + century = 1800 + elif number[0] in ['3','4']: + century = 1900 + elif number[0] in ['5','6']: + century = 2000 + else: + raise stdnum.exceptions.ValidationError("Wrong first number of IK: %s" % number) + year = century + int(number[1:3]) + month = int(number[3:5]) + day = int(number[5:7]) + return datetime.date(year,month,day) + + +def get_check(number): + checksum = int(number[9]) + for i, n in enumerate(number[:9]): + checksum += int(n) * (i+1) + check = checksum % 11 + if check == 10: + checksum = 0 + for i, n in enumerate(number[:7]): + checksum += int(n) * (i + 3) + for i, n in enumerate(number[7:10]): + checksum += int(n) * (i + 1) + check = checksum % 11 + check = check % 10 + return str(check) + + +def validate(number): + if len(number) != 11: + raise stdnum.exceptions.InvalidLength() + if not number.isdigit(): + raise stdnum.exceptions.InvalidFormat() + get_birth_date(number) + check = get_check(number) + if check != number[10]: + raise stdnum.exceptions.InvalidChecksum() + return number + + +def is_valid(number): + try: + return bool(validate(number)) + except ValidationError, ValueError: + return False + diff --git a/tests/test_ee_ik.doctest b/tests/test_ee_ik.doctest new file mode 100644 index 00000000..9c15471e --- /dev/null +++ b/tests/test_ee_ik.doctest @@ -0,0 +1,103 @@ +test_ee_ik.doctest - test for estonian personal id + +Copyright (C) 2013 Arthur de Jong +Copyright (C) 2015 Tomas Karasek + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA + +>>> from stdnum.ee import ik +>>> import stdnum.exceptions +>>> ik.validate('36805280109') +'36805280109' +>>> ik.is_valid('36805280109') +True +>>> ik.get_birth_date('36805280109') +datetime.date(1968, 5, 28) +>>> ik.get_check('36805280109') +'9' +>>> ik.validate('86805280109') +Traceback (most recent call last): + File "", line 1, in + File "stdnum/ee/ik.py", line 79, in validate + get_birth_date(number) + File "stdnum/ee/ik.py", line 51, in get_birth_date + raise ValidationError("Wrong first number of IK: %s" % number) +ValidationError: Wrong first number of IK: 86805280109 +>>> ik.validate('36805280108') +Traceback (most recent call last): + File "", line 1, in + File "stdnum/ee/ik.py", line 82, in validate + raise InvalidChecksum() +InvalidChecksum: The number's checksum or check digit is invalid. +>>> ik.validate('368052801099') +Traceback (most recent call last): + File "", line 1, in + File "stdnum/ee/ik.py", line 76, in validate + raise stdnum.exceptions.InvalidLength() +InvalidLength: The number has an invalid length. +>>> ns = """ +... 36205030034 +... 36606130166 +... 38002090113 +... 36703010079 +... 36412140053 +... 37105250048 +... 35806110178 +... 38411280151 +... 38004160054 +... 37406220030 +... 37207010076 +... 46104090101 +... 47306160017 +... 35712020095 +... 35512240278 +... 37111070056 +... 36003050128 +... 34508136020 +... 37112300117 +... 37205120111 +... 36708120106 +... 36204130100 +... 36805280109 +... 36404240119 +... 37609300174 +... 38407170099 +... 35903140121 +... 36912050058 +... 36706060097 +... 37909180161 +... 37210220129 +... 35803140053 +... 37709190107 +... 36306200109 +... 36208130099 +... 37611280079 +... 35806190146 +... 44909210102 +... 37104020141 +... 35907150159 +... 36412100145 +... 49105080018 +... 37406110083 +... 36304020091 +... 37106220087 +... 34706045216 +... 37503240119 +... 38310150127 +... 46708270050 +... """ +>>> [ ik.is_valid(n) for n in ns.split("\n") if n.strip() ] +[True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True, True]