目录
一、引言
在公安、民政、保险及教育等领域的日常工作中,批量计算人员年龄是一项常见但繁琐的任务,传统的手工处理方式不仅效率低下,还容易因人为操作导致错误。为此,我们开发了基于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_())
欢迎留言沟通交流!