Fundamentals 5 min read

Generate Valid Chinese ID Numbers with Python: Step-by-Step Guide

This tutorial explains the structure of Chinese citizen ID numbers, details the ISO 7064 checksum calculation, and provides Python code to generate random valid IDs and verify existing ones, covering area codes, birth dates, sequence and gender digits.

Python Programming Learning Circle
Python Programming Learning Circle
Python Programming Learning Circle
Generate Valid Chinese ID Numbers with Python: Step-by-Step Guide

01 ID Number Composition

According to GB 11643-1999, a Chinese citizen ID consists of 17 digits plus a checksum digit. The 18‑digit format includes:

Region code : administrative division code of the resident's household registration (e.g., 110102 for Beijing‑Xicheng). For Hong Kong, Macau, Taiwan only province‑level code is used.

Birthdate code : year (4 digits), month (2 digits), day (2 digits) of the Gregorian calendar.

Sequence code : a two‑digit number assigned to people born on the same day in the same region.

Gender code : odd for male, even for female.

Checksum digit : calculated using ISO 7064:1983 MOD 11‑2; if the result is 10, it is represented by "X".

02 Checksum Calculation Method

The checksum is derived by weighting each of the first 17 digits, summing them, and applying the MOD 11‑2 algorithm.

<code>def get_check_digit(id_number):
    """Calculate the checksum digit for a Chinese ID."""
    check_sum = 0
    for i in range(0, 17):
        check_sum += ((1 << (17 - i)) % 11) * int(id_number[i])
    check_digit = (12 - (check_sum % 11)) % 11
    return check_digit if check_digit < 10 else 'X'
</code>

03 Random ID Generation

Using the composition rules, the following class generates a random valid ID. The sex parameter (0 for female, 1 for male) determines the gender digit.

<code>@classmethod
def generate_id(cls, sex=0):
    """Generate a random Chinese ID number."""
    # Random region code (6 digits)
    id_number = str(random.choice(list(const.AREA_INFO.keys())))
    # Random birthdate between 1960‑01‑01 and 2000‑12‑30
    start, end = datetime.strptime("1960-01-01", "%Y-%m-%d"), datetime.strptime("2000-12-30", "%Y-%m-%d")
    birth_days = datetime.strftime(start + timedelta(random.randint(0, (end - start).days + 1)), "%Y%m%d")
    id_number += str(birth_days)
    # Sequence code (2 digits)
    id_number += str(random.randint(10, 99))
    # Gender code (1 digit)
    id_number += str(random.randrange(sex, 10, step=2))
    # Checksum digit
    return id_number + str(cls(id_number).get_check_digit())
</code>

04 Utility Functions

The script also provides a simple test harness to generate an ID and display its components.

<code>if __name__ == '__main__':
    random_sex = random.randint(0, 1)
    print(IdNumber.generate_id(random_sex))
    print(IdNumber('410326199507103197').area_id)
    print(IdNumber('410326199507103197').get_area_name())
    print(IdNumber('410326199507103197').get_birthday())
    print(IdNumber('410326199507103197').get_age())
    print(IdNumber('410326199507103197').get_sex())
    print(IdNumber('410326199507103197').get_check_digit())
    print(IdNumber.verify_id('410326199507103198'))
</code>
Algorithmdata validationchecksumID numberrandom generation
Python Programming Learning Circle
Written by

Python Programming Learning Circle

A global community of Chinese Python developers offering technical articles, columns, original video tutorials, and problem sets. Topics include web full‑stack development, web scraping, data analysis, natural language processing, image processing, machine learning, automated testing, DevOps automation, and big data.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.