分析

根据实际可能出现的排班情况,分成按天排班考勤与跨天排班考勤两种情况。

按天排班考勤

  • 考勤的开始与结束都在一天时间内
  • 一天时间内可能会要求多次打卡

跨天排班考勤

  • 考勤的开始与结束可能持续数天
  • 数天时间内可能会要求多次打卡

若打卡时间早于排班开始时间属于正常上班打卡,晚于排班开始时间属于迟到打卡。当天开始时(或设定一个差值范围时间)到排班开始时间打卡属于正常打卡。

若打卡时间早于排班结束时间属于早退打卡,晚于排班结束时间属于正常下班打卡。排班结束时间到当天结束时(或设定一个差值范围时间)未打卡属于缺卡。

start time              end time
      +---------------------+
      |                     |
----------------------------------------
   ↑
time pointer

算法设计

/* 方案一 */
// 查询是否有上班打卡
// 查询是否有下班打卡
// 判断上班卡与下班卡是否一致
// 不一致说明为跨天卡,查询上班打卡记录
// 若有记录则在原记录中插入下班打卡记录
// 若无记录则直接新增记录
const store: {
    key: "19970101",
    value: []
}
for ( const paiban of paiban) {
    for ( const daka of daka) {
        if (date(paiban) === date(daka) {
            if (daka <= paiban) {
                正常
            } else {
                迟到
            }
            delete daka
        }
    }
    if (!paiban) {
        缺卡
    }
}
for (const daka of data) {
    加班
}

/* 方案二 */
查询是否有上班卡,
判断
查询是否有下班卡,
判断
直接新增打卡,标记为上班卡还是下班卡,是早退、缺勤还是迟到。
将排班开始时间只保留日期,将上班的时间只保留日期,

上班考勤与下班考勤时间分开计算。算法一致。

方案三:只查询三个关键时间段并将三个时间段进行组合

当前时间的左值、当前时间的右值、当前时间位于的值。查询左值时,仅查询距离左值差值最小的值,查询右值的时候,仅查询距离右值差值最小的值,查询中间值时,则查询当前时间落于的区间。

时间问题

本节阐述数据库时间与本地时间的相关问题。

需要注意以下几点:

  • 浏览器通过new Date()拿到的时间为UTC时间
  • 通过navicat(电脑本地时间为+8:00时区)、+8:00时区的UTC格式等方式存储的时间都是非UTC时间,而是+8:00时区时间
  • 数据库+8:00的字段与new Date()做比较时、或需要格式化展示时,需要将数据库字段的时间减去8小时
  • 建议通过unix时间戳的方式存储数据。通过new Date().valueOf()可以获取unix时间戳
  • 任何+8:00时区(或非UTC标准时区)的时间选择操作,都需要减去对应的时区偏移以获取unix时间。
  • 严禁在统一时区的数据表字段上使用非统一时区。例如在某一表中的字段中既传入+8:00时区时间又传入UTC时区时间。这是绝对禁止的行为!