PyQt批量年龄计算工具:从身份证到指定日期的周岁处理

目录

一、引言

二、GUI界面设计

1.相关提示

2.效果演示

3.界面设计.py

三、主要程序详解

1.导入相关模块

2.初始化设置

3."日"选项的设置

4.年龄(周岁)的计算

5.自定义函数

四、总程序代码


一、引言

在公安、民政、保险及教育等领域的日常工作中,批量计算人员年龄是一项常见但繁琐的任务,传统的手工处理方式不仅效率低下,还容易因人为操作导致错误。为此,我们开发了基于PyQt框架的批量年龄(周岁)计算工具,该工具能够从18位身份证号中自动提取出生日期(第7-14位为YYYYMMDD格式),并结合用户指定的目标日期,高效、精准地计算出周岁年龄。同时支持将结果直接复制导出,便于后续数据分析与系统集成。无论是公安系统的户籍核查、保险行业的保费核保,还是教育机构的学生年龄统计,本工具都能提供标准化、可复用的解决方案,助力各行业在数字化转型中实现效率提升。

二、GUI界面设计

使用PyQt5进行界面的搭建,界面如下:

初始界面搭建采用极简风格 。当**批量输入(也可直接从excel中复制粘贴)**合法的身份证号码后,若其合法,点击"计算"后会在右侧给出对应年龄(周岁)结果;否则,会告知用户输入身份证号码存在不合法项并提示重新输入。

需要注意的是:该计算工具会结合用户指定的目标日期,高效、精准地计算出周岁年龄 。如上图红框所示:当两者均为2000年出生,得到的年龄相差为1,原因在于前者是4月份出生(到2025年的10月7日满周岁),后者是11月份出生(到2025年的10月7日未满周岁)

1.相关提示

在未输入身份证和未选择指定日期,进行"计算"操作后,均会给出提示;当用户输入的身份证存在长度错误或特殊字符时,提示"输入身份证有误,请重新输入"。

2.效果演示

**3.**界面设计.py

通过pyuic5产生的GUI界面代码jiemian.py如下:

python 复制代码
# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'jiemian.ui'
#
# Created by: PyQt5 UI code generator 5.15.11
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets


class Ui_Form(object):
    def setupUi(self, Form):
        Form.setObjectName("Form")
        Form.setEnabled(True)
        Form.resize(360, 450)
        Form.setMinimumSize(QtCore.QSize(360, 450))
        Form.setMaximumSize(QtCore.QSize(360, 450))
        icon = QtGui.QIcon()
        icon.addPixmap(QtGui.QPixmap(":/image1.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
        Form.setWindowIcon(icon)
        self.label_5 = QtWidgets.QLabel(Form)
        self.label_5.setGeometry(QtCore.QRect(210, 40, 141, 31))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(16)
        self.label_5.setFont(font)
        self.label_5.setObjectName("label_5")
        self.label_8 = QtWidgets.QLabel(Form)
        self.label_8.setGeometry(QtCore.QRect(130, 10, 251, 31))
        font = QtGui.QFont()
        font.setFamily("Adobe Arabic")
        font.setPointSize(18)
        font.setBold(False)
        font.setWeight(50)
        self.label_8.setFont(font)
        self.label_8.setObjectName("label_8")
        self.label_10 = QtWidgets.QLabel(Form)
        self.label_10.setGeometry(QtCore.QRect(290, 30, 71, 51))
        self.label_10.setText("")
        self.label_10.setPixmap(QtGui.QPixmap(":/image1.png"))
        self.label_10.setObjectName("label_10")
        self.textEdit = QtWidgets.QTextEdit(Form)
        self.textEdit.setGeometry(QtCore.QRect(30, 110, 141, 201))
        self.textEdit.setObjectName("textEdit")
        self.textEdit_2 = QtWidgets.QTextEdit(Form)
        self.textEdit_2.setGeometry(QtCore.QRect(200, 110, 141, 201))
        self.textEdit_2.setObjectName("textEdit_2")
        self.label = QtWidgets.QLabel(Form)
        self.label.setGeometry(QtCore.QRect(30, 85, 121, 21))
        self.label.setObjectName("label")
        self.label_2 = QtWidgets.QLabel(Form)
        self.label_2.setGeometry(QtCore.QRect(200, 90, 54, 12))
        self.label_2.setObjectName("label_2")
        self.pushButton = QtWidgets.QPushButton(Form)
        self.pushButton.setGeometry(QtCore.QRect(30, 410, 311, 23))
        self.pushButton.setObjectName("pushButton")
        self.comboBox = QtWidgets.QComboBox(Form)
        self.comboBox.setGeometry(QtCore.QRect(40, 360, 67, 22))
        self.comboBox.setObjectName("comboBox")
        self.comboBox_2 = QtWidgets.QComboBox(Form)
        self.comboBox_2.setGeometry(QtCore.QRect(150, 360, 67, 22))
        self.comboBox_2.setObjectName("comboBox_2")
        self.comboBox_3 = QtWidgets.QComboBox(Form)
        self.comboBox_3.setGeometry(QtCore.QRect(260, 360, 67, 22))
        self.comboBox_3.setObjectName("comboBox_3")
        self.label_3 = QtWidgets.QLabel(Form)
        self.label_3.setGeometry(QtCore.QRect(110, 360, 16, 21))
        self.label_3.setObjectName("label_3")
        self.label_4 = QtWidgets.QLabel(Form)
        self.label_4.setGeometry(QtCore.QRect(220, 360, 21, 21))
        self.label_4.setObjectName("label_4")
        self.label_6 = QtWidgets.QLabel(Form)
        self.label_6.setGeometry(QtCore.QRect(330, 360, 21, 21))
        self.label_6.setObjectName("label_6")
        self.label_7 = QtWidgets.QLabel(Form)
        self.label_7.setGeometry(QtCore.QRect(30, 330, 121, 31))
        self.label_7.setObjectName("label_7")

        self.retranslateUi(Form)
        QtCore.QMetaObject.connectSlotsByName(Form)

    def retranslateUi(self, Form):
        _translate = QtCore.QCoreApplication.translate
        Form.setWindowTitle(_translate("Form", "Age_cal"))
        self.label_5.setText(_translate("Form", "Designed By"))
        self.label_8.setText(_translate("Form", "年龄计算"))
        self.label.setText(_translate("Form", "请输入身份证号码:"))
        self.label_2.setText(_translate("Form", "年龄如下:"))
        self.pushButton.setText(_translate("Form", "计算"))
        self.label_3.setText(_translate("Form", "年"))
        self.label_4.setText(_translate("Form", "月"))
        self.label_6.setText(_translate("Form", "日"))
        self.label_7.setText(_translate("Form", "请选择指定日期:"))
import ziyuan_rc

三、主要程序详解

1.导入相关模块

python 复制代码
import sys, time
from jiemian import *
from PyQt5.QtWidgets import QApplication, QWidget
# 保持窗口大小和qtdesigner中的一致
from PyQt5 import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)

导入前端页面设计文件:jiemian.py;不懂为啥需要导入Qtcore的,请看************************************************************************************************************************************************************************************************************************************************************一键曝光:Python+PyQt实现的文件目录透视镜************************************************************************************************************************************************************************************************************************************************************

2.初始化设置

python 复制代码
    def __init__(self):
        super(QWidget, self).__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(self.jisuan)
        self.comboBox.currentIndexChanged.connect(self.day_show)  # 年份选项发生改变
        self.comboBox_2.currentIndexChanged.connect(self.day_show)  # 月份选项发生改变

        self.comboBox.addItem('请选择')
        self.comboBox_2.addItem('请选择')

        # 针对"年"
        self.cur_nian = time.strftime("%Y", time.localtime())
        # 使用列表推导式增添选项
        self.comboBox.addItems([str(int(self.cur_nian) + i) for i in range(-5, 6)])  # 年
        self.comboBox_2.addItems([str(i) for i in range(1, 13)])  # 月

pushbutton绑定于jisuan;当用户改变年度/月份时,对应的"日"也需要紧随变化,故将其绑定于day_show ;同时在初始化时将年份comboBox和月份comboBox_2添加首选项"请选择",日comboBox暂时不做处理;接着通过time.strftime获取当前年份并存储于cur_nian中;以当前年份为时间中点,使用列表推导式往前往后各推5年 添加至comboBox中;最后再通过列表推导式添加12个月份。

3."日"选项的设置

python 复制代码
    def day_show(self):
    """主要对日进行设置,因为其不仅与月份有关,还与年份有关(闰年的2月)"""
        self.comboBox_3.clear()
        self.comboBox_3.addItem('请选择')
        yue_text = self.comboBox_2.currentText()  # 判断用户选择的是哪个月
        if yue_text in ['1', '3', '5', '7', '8', '10', '12']:  # 31天的月份
            self.comboBox_3.addItems([str(i) for i in range(1, 32)])
        elif yue_text in ['4', '6', '9', '11']:  # 30天的月份
            self.comboBox_3.addItems(str(i) for i in range(1, 31))
        elif yue_text == '2':  # 针对2月要特殊处理
            if self.comboBox.currentIndex() != 0:  # 除去年份为"请选择"的特殊情况
                if year_judge(self.comboBox.currentText()):  # 为闰年,2月为29天
                    self.comboBox_3.addItems([str(i) for i in range(1, 30)])
                else:  # 不为闰年,2月为28天
                    self.comboBox_3.addItems([str(i) for i in range(1, 29)])
        else:  # 表示月份的"请选择"选项
            pass

与其他combobox一样,combobox_3"日下拉框"也需要clear()和添加首选项"请选择";combobox_3其不仅取决于"年下拉框"combobox是否为闰年,而且还取决于"月下拉框"combobox_2的选择(有31天的月份,也有30天的月份);所以先判断combobox_2的text是否在31天和30天的月份中,如果存在,直接使用列表推导式additems即可;否则如果为2月,还需通过自定义函数year_judge判断当前年份是否为闰年;如果为闰年,则列表推导式产生29天,否则产生28天;此时,combobox_3未讨论情况只剩下"请选择"选项,pass即可。

4.年龄(周岁)的计算

python 复制代码
    def jisuan(self):
        shuru = self.textEdit.toPlainText()  # 读取的默认类型为str

        if shuru != "": # 用户输入不为空时
            if (self.comboBox.currentIndex()!=0) and(self.comboBox_2.currentIndex()!=0) and (self.comboBox_3.currentIndex()!=0): # 用户做出年月日的选择
                shuru_nian = self.comboBox.currentText()
                shuru_yue = self.comboBox_2.currentText()
                shuru_ri = self.comboBox_3.currentText()
                zhiding_riqi = riqi_return(shuru_nian,shuru_yue,shuru_ri) # 合并为YYYYMMDD的形式

                shuru_list = shuru.split()  # 以换行符分割
                riqi = [i[6:14] for i in shuru_list] # 截取所有身份证的8位日期

                jieguo  =[] # 年龄差存放
                for i in riqi:
                    if (len(i) == 8) and i.isdigit(): # 长度为8且均为数字
                        jieguo.append(niancha_cal(zhiding_riqi, i))
                    else:
                        QtWidgets.QMessageBox.critical(self, "提示", "输入身份证有误,请重新输入!")
                        break

                self.textEdit_2.clear() # 清除上次结果
                for item in jieguo:
                    self.textEdit_2.append(str(item))
            else:
                QtWidgets.QMessageBox.critical(self, "提示", "请选择指定日期!")
        else:
            QtWidgets.QMessageBox.critical(self, "提示", "请输入身份证号!")

当用户输入不为空时,判断用户是否进行了"年月日"的选择(依据item的索引 );若用户已经进行选择,则读取年月日并存储,通过调用自定义函数riqi_return从而返回YYYYMMDD的日期规范格式;再通过对用户输入的所有身份证进行切片操作,获取8位日期,并与上述YYYYMMDD通过自定义函数niancha_cal进行比较和计算,将得到的结果添加至jieguo中;最后通过循环显示到textedit_2中。

5.自定义函数

python 复制代码
def year_judge(year):
    """判断用户输入是否为闰年"""
    if (int(year)%4==0) and (int(year)%100!=0):
        return True
    elif int(year)%400==0:
        return True
    else:
        return False

闰年的标志:能被4整除的同时,但不能被100整除;或者是能被400直接整除。

python 复制代码
def riqi_return(nian, yue, ri):
    """将年月日三数字转换合并为YYYYMMDD形式"""
    if (int(yue)<10): # 单月形式
        if (int(ri)<10): # 单日
            return nian+'0'+yue+'0'+ri # 补零操作
        else:
            return nian+'0'+yue+ri
    else:
        if (int(ri) < 10):
            return nian+yue+'0'+ri
        else:
            return nian+yue+ri

通过分支结构,在单数字前进行补零,最后将字符串拼接即可得到YYYYMMDD形式。

python 复制代码
def niancha_cal(date1, date2):
    # 默认date1先于date2
    if int(date1)<int(date2): # 交换两者顺序
        temp = date1
        date1 = date2
        date2 = temp

    if int(date1[4:6]) < int(date2[4:6]): # 判断月的大小关系
        return int(date1[0:4])-int(date2[0:4])-1 # 不满周岁得减一
    elif int(date1[4:6]) > int(date2[4:6]):
        return int(date1[0:4])-int(date2[0:4])
    else:
        if int(date1[6:8]) < int(date2[6:8]): # 进一步判断"日"的大小关系
            return int(date1[0:4]) - int(date2[0:4]) - 1  # 不满周岁得减一
        else:
            return int(date1[0:4]) - int(date2[0:4])

默认date1先于date2,否则进行交换;接下来截取月份和日进行比较,最终截取年份相减,根据是否满周岁判断是否多减一。

四、总程序代码

python 复制代码
import sys, time
from jiemian import *
from PyQt5.QtWidgets import QApplication, QWidget
# 保持窗口大小和qtdesigner中的一致
from PyQt5 import QtCore
QtCore.QCoreApplication.setAttribute(QtCore.Qt.AA_EnableHighDpiScaling)

class window(QWidget, Ui_Form):
    def __init__(self):
        super(QWidget, self).__init__()
        self.setupUi(self)

        self.pushButton.clicked.connect(self.jisuan)
        self.comboBox.currentIndexChanged.connect(self.day_show)  # 年份选项发生改变
        self.comboBox_2.currentIndexChanged.connect(self.day_show)  # 月份选项发生改变

        self.comboBox.addItem('请选择')
        self.comboBox_2.addItem('请选择')

        # 针对"年"
        self.cur_nian = time.strftime("%Y", time.localtime())
        # 使用列表推导式增添选项
        self.comboBox.addItems([str(int(self.cur_nian) + i) for i in range(-5, 6)])  # 年
        self.comboBox_2.addItems([str(i) for i in range(1, 13)])  # 月

    def day_show(self):
        self.comboBox_3.clear()
        self.comboBox_3.addItem('请选择')
        yue_text = self.comboBox_2.currentText()  # 判断用户选择的是哪个月
        if yue_text in ['1', '3', '5', '7', '8', '10', '12']:  # 31天的月份
            self.comboBox_3.addItems([str(i) for i in range(1, 32)])
        elif yue_text in ['4', '6', '9', '11']:  # 30天的月份
            self.comboBox_3.addItems(str(i) for i in range(1, 31))
        elif yue_text == '2':  # 针对2月要特殊处理
            if self.comboBox.currentIndex() != 0:  # 除去年份为"请选择"的特殊情况
                if year_judge(self.comboBox.currentText()):  # 为闰年,2月为29天
                    self.comboBox_3.addItems([str(i) for i in range(1, 30)])
                else:  # 不为闰年,2月为28天
                    self.comboBox_3.addItems([str(i) for i in range(1, 29)])
        else:  # 表示月份的"请选择"选项
            pass

    def jisuan(self):
        shuru = self.textEdit.toPlainText()  # 读取的默认类型为str

        if shuru != "": # 用户输入不为空时
            if (self.comboBox.currentIndex()!=0) and(self.comboBox_2.currentIndex()!=0) and (self.comboBox_3.currentIndex()!=0): # 用户做出年月日的选择
                shuru_nian = self.comboBox.currentText()
                shuru_yue = self.comboBox_2.currentText()
                shuru_ri = self.comboBox_3.currentText()
                zhiding_riqi = riqi_return(shuru_nian,shuru_yue,shuru_ri) # 合并为YYYYMMDD的形式

                shuru_list = shuru.split()  # 以换行符分割
                riqi = [i[6:14] for i in shuru_list] # 截取所有身份证的8位日期

                jieguo  =[] # 年龄差存放
                for i in riqi:
                    if (len(i) == 8) and i.isdigit(): # 长度为8且均为数字
                        jieguo.append(niancha_cal(zhiding_riqi, i))
                    else:
                        QtWidgets.QMessageBox.critical(self, "提示", "输入身份证有误,请重新输入!")
                        break

                self.textEdit_2.clear() # 清除上次结果
                for item in jieguo:
                    self.textEdit_2.append(str(item))
            else:
                QtWidgets.QMessageBox.critical(self, "提示", "请选择指定日期!")
        else:
            QtWidgets.QMessageBox.critical(self, "提示", "请输入身份证号!")

def year_judge(year):
    """判断用户输入是否为闰年"""
    if (int(year)%4==0) and (int(year)%100!=0):
        return True
    elif int(year)%400==0:
        return True
    else:
        return False

def riqi_return(nian, yue, ri):
    """将年月日三数字转换合并为YYYYMMDD形式"""
    if (int(yue)<10): # 单月形式
        if (int(ri)<10): # 单日
            return nian+'0'+yue+'0'+ri # 补零操作
        else:
            return nian+'0'+yue+ri
    else:
        if (int(ri) < 10):
            return nian+yue+'0'+ri
        else:
            return nian+yue+ri

def niancha_cal(date1, date2):
    # 默认date1先于date2
    if int(date1)<int(date2): # 交换两者顺序
        temp = date1
        date1 = date2
        date2 = temp

    if int(date1[4:6]) < int(date2[4:6]): # 判断月的大小关系
        return int(date1[0:4])-int(date2[0:4])-1 # 不满周岁得减一
    elif int(date1[4:6]) > int(date2[4:6]):
        return int(date1[0:4])-int(date2[0:4])
    else:
        if int(date1[6:8]) < int(date2[6:8]): # 进一步判断"日"的大小关系
            return int(date1[0:4]) - int(date2[0:4]) - 1  # 不满周岁得减一
        else:
            return int(date1[0:4]) - int(date2[0:4])

if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = window()
    w.show()
    sys.exit(app.exec_())

欢迎留言沟通交流!

相关推荐
B站_计算机毕业设计之家3 小时前
Python+Flask+Prophet 汽车之家二手车系统 逻辑回归 二手车推荐系统 机器学习(逻辑回归+Echarts 源码+文档)✅
大数据·人工智能·python·机器学习·数据分析·汽车·大屏端
MoRanzhi12033 小时前
SciPy傅里叶变换与信号处理教程:数学原理与Python实现
python·机器学习·数学建模·数据分析·信号处理·傅里叶分析·scipy
XXX-X-XXJ3 小时前
三、从 MinIO 存储到 OCR 提取,再到向量索引生成
人工智能·后端·python·ocr
2401_878454533 小时前
Vue 核心特性详解:计算属性、监听属性与事件交互实战指南
前端·vue.js·交互
爱偷懒的。。4 小时前
基于 WebSocket 协议的实时弹幕通信机制分析-抖音
网络·python·websocket·网络协议·学习·js
cllsse4 小时前
pytest学习
软件测试·python·pytest
海琴烟Sunshine4 小时前
leetcode 88.合并两个有序数组
python·算法·leetcode
知识分享小能手5 小时前
微信小程序入门学习教程,从入门到精通,自定义组件与第三方 UI 组件库(以 Vant Weapp 为例) (16)
前端·学习·ui·微信小程序·小程序·vue·编程
B站_计算机毕业设计之家5 小时前
数据分析:Python懂车帝汽车数据分析可视化系统 爬虫(Django+Vue+销量分析 源码+文档)✅
大数据·爬虫·python·数据分析·汽车·可视化·懂车帝