You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

人力资源应用开发:MySQL考勤加班计算与时间格式化实现咨询

嘿,我来帮你搞定这两个核心需求!先从你提到的格式化时间输入框问题入手,再聊MySQL里考勤加班时长的计算逻辑。

一、修复并优化JFormattedTextField的时间输入限制

你当前的代码里createFormatter(" ##:##:##")的掩码配置不够严谨,而且缺少合法时间的验证逻辑(比如小时不能超过23,分钟/秒不能超过59)。这里给你一套完整的初始化方案,用MaskFormatter严格限制HH:mm:ss格式,同时确保输入的时间合法:

首先实现一个靠谱的createFormatter方法:

private MaskFormatter createFormatter(String mask) throws ParseException {
    MaskFormatter formatter = new MaskFormatter(mask);
    formatter.setPlaceholderCharacter('0'); // 用0填充未输入的空位,确保格式完整
    formatter.setValidCharacters("0123456789"); // 只允许输入数字
    // 添加自定义验证器,确保输入的是合法的HH:mm:ss时间
    formatter.setValidator(new javax.swing.JFormattedTextField.AbstractFormatter() {
        @Override
        public Object stringToValue(String text) throws ParseException {
            // 用正则匹配合法的时间格式
            if (!text.matches("([01]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)")) {
                throw new ParseException("请输入合法的HH:mm:ss格式时间", 0);
            }
            return text;
        }

        @Override
        public String valueToString(Object value) throws ParseException {
            return value != null ? value.toString() : "00:00:00";
        }
    });
    return formatter;
}

然后是初始化时间输入框和日期输入框的完整代码:

private void initInputComponents() {
    try {
        // 初始化时间输入框(严格限制HH:mm:ss格式)
        jFormattedTextField1 = new JFormattedTextField(createFormatter("##:##:##"));
        // 设置默认值为当前系统时间
        Date currentDate = new Date();
        SimpleDateFormat timeFormatter = new SimpleDateFormat("HH:mm:ss");
        jFormattedTextField1.setValue(timeFormatter.format(currentDate));
        // 设置提示文本,引导用户输入
        jFormattedTextField1.setToolTipText("请输入HH:mm:ss格式的时间");
        // 添加输入合法性监听,非法输入时高亮提示
        jFormattedTextField1.addPropertyChangeListener("value", evt -> {
            if (jFormattedTextField1.isEditValid()) {
                jFormattedTextField1.setBackground(Color.WHITE);
            } else {
                jFormattedTextField1.setBackground(Color.PINK);
            }
        });

        // 初始化日期输入框(示例:yyyy-MM-dd格式)
        JFormattedTextField dateInput = new JFormattedTextField(new SimpleDateFormat("yyyy-MM-dd"));
        dateInput.setValue(currentDate);
        dateInput.setToolTipText("请输入yyyy-MM-dd格式的日期");
        // 记得将dateInput添加到你的界面容器中(比如JPanel)
    } catch (ParseException ex) {
        ex.printStackTrace();
        JOptionPane.showMessageDialog(null, "输入框初始化失败:" + ex.getMessage());
    }
}

二、MySQL中基于考勤数据计算加班时长

假设你的考勤表结构大致如下(可以根据实际业务调整字段):

CREATE TABLE attendance (
    id INT PRIMARY KEY AUTO_INCREMENT,
    emp_id INT NOT NULL COMMENT '员工ID',
    work_date DATE NOT NULL COMMENT '考勤日期',
    clock_in DATETIME NOT NULL COMMENT '上班打卡时间',
    clock_out DATETIME NOT NULL COMMENT '下班打卡时间',
    normal_daily_hours DECIMAL(5,2) DEFAULT 8.0 COMMENT '每日标准工作时长(小时)'
);

1. 基础加班时长计算(单位:小时)

核心思路是先计算实际工作时长,再减去标准时长,正数即为加班时长(避免出现负数值):

SELECT 
    emp_id,
    work_date,
    clock_in,
    clock_out,
    normal_daily_hours,
    -- 计算实际工作时长(转换为小时)
    TIMESTAMPDIFF(SECOND, clock_in, clock_out) / 3600 AS actual_work_hours,
    -- 计算加班时长,若实际时长≤标准时长则加班为0
    GREATEST(0, TIMESTAMPDIFF(SECOND, clock_in, clock_out) / 3600 - normal_daily_hours) AS overtime_hours
FROM attendance;

2. 格式化加班时长为HH:mm:ss格式

如果需要把加班时长转换成HH:mm:ss的可读格式,可以用嵌套查询实现:

SELECT 
    emp_id,
    work_date,
    CONCAT(
        LPAD(FLOOR(overtime_seconds / 3600), 2, '0'), ':',
        LPAD(FLOOR((overtime_seconds % 3600) / 60), 2, '0'), ':',
        LPAD(overtime_seconds % 60, 2, '0')
    ) AS overtime_duration
FROM (
    SELECT 
        emp_id,
        work_date,
        -- 计算加班总秒数
        GREATEST(0, TIMESTAMPDIFF(SECOND, clock_in, clock_out) - normal_daily_hours * 3600) AS overtime_seconds
    FROM attendance
) AS overtime_calc;

3. 进阶:区分工作日/休息日加班

如果需要区分工作日和休息日加班(比如休息日加班按1.5倍计算),可以结合DAYOFWEEK函数判断日期是否为周末:

SELECT 
    emp_id,
    work_date,
    -- 判断是否为周末(周日=1,周六=6)
    CASE WHEN DAYOFWEEK(work_date) IN (1,6) THEN '休息日' ELSE '工作日' END AS work_type,
    -- 基础加班时长
    GREATEST(0, TIMESTAMPDIFF(SECOND, clock_in, clock_out) / 3600 - normal_daily_hours) AS base_overtime,
    -- 调整后的加班时长(休息日按1.5倍计算)
    GREATEST(0, TIMESTAMPDIFF(SECOND, clock_in, clock_out) / 3600 - normal_daily_hours) * 
        CASE WHEN DAYOFWEEK(work_date) IN (1,6) THEN 1.5 ELSE 1 END AS adjusted_overtime
FROM attendance;

内容的提问来源于stack exchange,提问作者Abdallah zoubi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 06:38:48