diff options
author | Jiangge Zhang <tonyseek@gmail.com> | 2014-10-06 16:27:44 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2014-10-06 20:58:26 +0200 |
commit | 141d576c6e9ff90a1c7f8e314763399d1ae0693a (patch) | |
tree | 0fbf8b315fb26cc2645fea07cd6e0ede5e6f6519 /stdnum/cn | |
parent | 10ae5481a79aeed997eec4314c0e4681c7bf833e (diff) |
Support the Resident Identity Card Number of People's Republic China
Diffstat (limited to 'stdnum/cn')
-rw-r--r-- | stdnum/cn/ric.py | 106 |
1 files changed, 106 insertions, 0 deletions
diff --git a/stdnum/cn/ric.py b/stdnum/cn/ric.py new file mode 100644 index 0000000..800a94b --- /dev/null +++ b/stdnum/cn/ric.py @@ -0,0 +1,106 @@ +# ric.py - functions for handling Chinese Resident Identity Card Number +# +# Copyright (C) 2014 Jiangge Zhang +# +# 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 + +"""RIC No. (Chinese Resident Identity Card Number). + +The RIC No. is the unique identifier for issued to China (PRC) residents. + +The number consist of 18 digits in four sections. The first 6 digits refers to +the resident's location, followed by 8 digits represeting the resident's birth +day in the form YYYY-MM-DD. The next 3 digits is the order code which is the +code used to disambiguate people with the same date of birth and address code. +Men are assigned to odd numbers, women assigned to even numbers. The final +digit is the checksum. + +>>> validate('360426199101010071') +'360426199101010071' +""" + +import datetime + +from stdnum.exceptions import ( + ValidationError, InvalidLength, InvalidFormat, InvalidChecksum, + InvalidComponent) +from stdnum.util import clean + + +def compact(number): + """Convert the number to the minimal representation. This strips the + number of any valid separators and removes surrounding whitespace.""" + return clean(number).upper().strip() + + +def get_birth_date(number): + """Split the date parts from the number and return the birth date. + Note that in some cases it may return the registration date instead of + the birth date and it may be a century off.""" + number = compact(number) + year = int(number[6:10]) + month = int(number[10:12]) + day = int(number[12:14]) + try: + return datetime.date(year, month, day) + except ValueError: + raise InvalidComponent() + + +def get_birth_place(number): + """Use the number to look up the place of birth of the person.""" + from stdnum import numdb + number = compact(number) + results = numdb.get('cn/loc').info(number[:6])[0][1] + if not results: + raise InvalidComponent() + return results + + +def calc_check_digit(number): + checksum = (1 - 2 * int(number[:-1], 13)) % 11 + return 'X' if checksum == 10 else str(checksum) + + +def validate(number): + """Checks to see if the number provided is a valid RIC numbers. This + checks the length, formatting and birth date and place.""" + number = compact(number) + if len(number) != 18: + raise InvalidLength() + if not number[:-1].isdigit(): + raise InvalidFormat() + if not number[-1].isdigit() and number[-1] != 'X': + raise InvalidFormat() + if number[-1] != calc_check_digit(number): + raise InvalidChecksum() + get_birth_date(number) + get_birth_place(number) + return number + + +def is_valid(number): + """Checks to see if the number provided is a valid RIC numbers. This + checks the length, formatting and birth date and place.""" + try: + return bool(validate(number)) + except ValidationError: + return False + + +def format(number): + """Reformat the passed number to the standard format.""" + return compact(number) |