本篇文章是假设请假是半天起步,如果人性化的公司可以支持小时维度的请假,那更简单直接相减
考虑情况:
1、午休时间是否过滤,不过滤的话也很简单,直接结束和开始时间相减,需要过滤的话就要考虑分段处理了,开始当天(开始时间和当天下班时间差值),结束当天(当天上班时间和结束时间差值),中间的天数(上班时间和下班时间差值)。此处需要注意如何跳过午休时间
2、节假日,应为每年的节假日其实是不固定的,正常情况都是当年下半年假日办公布下一年的休假日(法定假日,涉及调休),所以针对公司来说 OA 系统中都是人工录入的。这里维护一个列表,在数组中存在就跳过
开始
这里用到dayjs 用于时间的计算
const dayjs = require('dayjs')
const customParseFormat = require('dayjs/plugin/customParseFormat')
dayjs.extend(customParseFormat)
// 当年假期const holidayList = ['2023-06-17', '2023-06-18']
// 是否过滤午休时间,默认是跳过,可自行修改
const rest = true
// 上下班时间
const startWorkTime = '09:00'
const endWorkTime = '18:00'
// 午休息时间
const startFreeTime = '12:00'
const endFreeTime = '13:30'
function getTotal(options) {
// {
// 请假开始时间
// beginAt,
// 请假结束时间
// endAt,
// }
// 这里做了开始和结束时间的调换,也可以直接 return 根据业务自行选择
if (dayjs(options.beginAt).isAfter(dayjs(options.endAt)))
[options.beginAt, options.endAt] = [options.endAt, options.beginAt]
const restList = holidayList.map(d => dayjs(d, 'YYYY-MM-DD'))
let minute = 0
const diffDay = dayjs(options.endAt)
.startOf('d').diff(dayjs(options.beginAt).startOf('d'), 'd')
for (let i = 0; i <= diffDay; i++) {
const day = dayjs(options.beginAt).add(i, 'd').startOf('d')
if (restList.some(d => d.isSame(day, 'd'))) continue
// 上午上班时间
const a = dayjs(`${day.format('YYYY-MM-DD')} ${startWorkTime}`,
'YYYY-MM-DD HH:mm')
// 下午下班时间
const f = dayjs(`${day.format('YYYY-MM-DD')} ${endWorkTime}`,
'YYYY-MM-DD HH:mm')
// 上午午休开始时间
const ar = dayjs(`${day.format('YYYY-MM-DD')} ${startFreeTime}`,
'YYYY-MM-DD HH:mm')
// 下午午休结束时间
const fr = dayjs(`${day.format('YYYY-MM-DD')} ${endFreeTime}`,
'YYYY-MM-DD HH:mm')
let beginAt = dayjs(options.beginAt)
beginAt = beginAt.isBefore(a) ? a : beginAt.isAfter(f) ? f : beginAt
let endAt = dayjs(options.endAt)
endAt = endAt.isAfter(f) ? f : endAt
if (rest) {
beginAt = beginAt.isAfter(ar) && beginAt.isBefore(fr) ? fr : beginAt
endAt = endAt.isAfter(ar) && endAt.isBefore(fr) ? ar : endAt
}
let ranges = []
if (diffDay === 0) {
if (rest && beginAt.isBefore(ar) && endAt.isAfter(fr)) {
ranges = [[beginAt, ar], [fr, endAt]]
} else {
ranges = [[beginAt, endAt]]
}
} else if (i === 0) {
if (rest) {
ranges = beginAt.isBefore(ar) ?
[[beginAt, ar], [fr, f]] : [[beginAt, f]]
} else {
ranges = [[beginAt, f]]
}
} else if (i === diffDay) {
if (rest) {
ranges = endAt.isBefore(ar) ? [[a, endAt]] : [[a, ar], [fr, endAt]]
} else {
ranges = [[a, endAt]]
}
} else {
if (rest) {
ranges = [[a, ar], [fr, f]
} else {
ranges = [[a, f]]
}
}
minute += ranges.map(range => {
const diff = range[1].diff(range[0], 'minute')
if (diff < 0) {
return 0
}
return diff
}).reduce((a, b) => a + b, 0) }
const oh = parseFloat((minute / 60).toFixed(2))
const d = oh % 8 > 0 ?
oh % 8 < 4 ?
Math.floor(oh / 8) + 0.5
: Math.floor(oh / 8) + 1
: oh / 8
// oh 为原始时长, d 是按照 >0 但是<0.5 按 0.5天算,>0.5 按1天算,h是由天折算的请假时长
return { oh, d, h: d * 8 }
}