Python笔记 之 使用interval模块计算员工请假时间

闲来无事将之前用Oracle写的算法重新用Python编写了一遍,通过使用interval模块进一步简化了流程。

初始化参数

因为夏季作息和冬季作息时间表不一致,需要提前声明:

import datetime
import interval

# 设置夏季作息
# 夏季作息开始日期为 当年的5月1日
summerstartdatestring = '-'.join((datetime.datetime.strftime(datetime.datetime.now(),'%Y'),)+('5','1'))
summerstartdate = datetime.datetime.strptime(summerstartdatestring,'%Y-%m-%d')
# 夏季作息截止日期为 当年的10月1日
summerenddatestring = '-'.join((datetime.datetime.strftime(datetime.datetime.now(),'%Y'),)+('10','1'))
summerenddate = datetime.datetime.strptime(summerenddatestring,'%Y-%m-%d')
# 夏季作息时间区间(闭合区间)
summer = interval.Interval(summerstartdate,summerenddate)

# 设置作息时间
# 夏季作息时间安排
summermorningstart = '08:30:00'
summermorningend = '12:00:00'
summerafternoonstart = '14:30:00'
summerafternoonend = '18:00:00'
# 夏季作息,实际工作秒
summerseconds = int(60 * 60 * 7)
# 冬季作息时间安排
wintermorningstart = '08:30:00'
wintermorningend = '11:30:00'
winterafternoonstart = '14:00:00'
winterafternoonend = '17:30:00'
# 冬季作息,实际工作秒
winterseconds = int(60 * 60 * 6.5)
主函数

通过递归调用计算请假区间的有效时长,返回有效天数和秒数的元祖

def leaveBillTime(_starttime,_endtime):
    '''
    根据请假时间段计算请假时间
    :param _starttime: 起始时间
    :param _endtime: 结束时间
    :return: 请假时长(天,秒)
    '''

    # 日期格式转换
    leavestarttime = toDateTime(_starttime)
    leaveendtime = toDateTime(_endtime)
    # 获取实际请假时间点
    leavestarttime = effectiveStartTime(leavestarttime)
    leaveendtime = effectiveEndTime(leaveendtime)
    # 生成请假时间区间
    leavebilltime = interval.Interval(leavestarttime,leaveendtime)

    if leavebilltime in summer:
        # 请假时间区间在夏季作息区间
        leavebillday = (leaveendtime - leavestarttime).days
        if datetime.datetime.strftime(leavestarttime + datetime.timedelta(leavebillday),'%Y-%m-%d') == datetime.datetime.strftime(leaveendtime,'%Y-%m-%d'):
            # 夏季作息,起始时间点小于等于截止时间点
            # 返回实际(请假天数,实际请假秒数)
            return (leavebillday + round((effectiveStartSeconds(leavestarttime)+effectiveEndSeconds(leaveendtime)) / summerseconds,2) - 1,
                    summerseconds * (leavebillday - 1) + effectiveStartSeconds(leavestarttime) + effectiveEndSeconds(leaveendtime))
        else:
            # 夏季作息,起始时间点大于截止时间点
            # 返回实际(请假天数,实际请假秒数)
            return (leavebillday + round((effectiveStartSeconds(leavestarttime) + effectiveEndSeconds(leaveendtime)) / summerseconds, 2),
                    summerseconds * leavebillday + effectiveStartSeconds(leavestarttime) + effectiveEndSeconds(leaveendtime))
    elif summer in leavebilltime:
        # 请假时间区间横跨夏季作息时间
        # 使用递归调用将时间划分为夏季作息开始前,夏季作息,夏季作息后
        # 夏季作息前
        summerbefortime = leaveBillTime(leavestarttime,summerstartdate)
        summertime = leaveBillTime(summerstartdate,summerenddate)
        summeraftertime = leaveBillTime(summerenddate,leaveendtime)
        return (summerbefortime[0] + summertime[0] + summeraftertime[0],
                summerbefortime[1] + summertime[1] + summeraftertime[1])
    elif not leavebilltime.overlaps(summer):
        # 请假时间区间在冬季作息
        leavebillday = (leaveendtime - leavestarttime).days
        if datetime.datetime.strftime(leavestarttime + datetime.timedelta(leavebillday),'%Y-%m-%d') == datetime.datetime.strftime(leaveendtime,'%Y-%m-%d'):
            # 冬季作息,请假起始时间点小于等于截止时间点
            # 返回实际(请假天数,实际请假秒数)
            return (leavebillday + round((effectiveStartSeconds(leavestarttime)+effectiveEndSeconds(leaveendtime)) / winterseconds,2)-1,
                    winterseconds * (leavebillday - 1) + effectiveStartSeconds(leavestarttime)+effectiveEndSeconds(leaveendtime))
        else:
            # 冬季作息,请假起始时间点小于等于截止时间点
            # 返回实际(请假天数,实际请假秒数)
            return (leavebillday + round(
                (effectiveStartSeconds(leavestarttime) + effectiveEndSeconds(leaveendtime)) / winterseconds, 2),
                    winterseconds * leavebillday + effectiveStartSeconds(leavestarttime) + effectiveEndSeconds(
                        leaveendtime))
    else:
        # 请假时间区间横跨冬季夏季作息
        if leavestarttime in summer:
            # 起始时间在夏季作息
            summerbilltime = leaveBillTime(leavestarttime,summerenddate)
            winterbilltime = leavebilltime(summerenddate,leaveendtime)
            return (summerbilltime[0] + winterbilltime[0],
                    summerbilltime[1] + winterbilltime[1])
        if leaveendtime in summer:
            # 截止时间在夏季作息
            summerbilltime = leaveBillTime(summerstartdate, leaveendtime)
            winterbilltime = leavebilltime(leavestarttime, summerstartdate)
            return (summerbilltime[0] + winterbilltime[0],
                    summerbilltime[1] + winterbilltime[1])
辅助函数

1,请假开始当日的剩余秒数

def effectiveStartSeconds(_datetime):
    '''
    计算请假起始当天的剩余有效请假时间
    :param _datetime: 请假起始当天的时间
    :return: 剩余秒
    '''

    # 判断是否是夏季作息
    summerflag = isSummer(_datetime)

    if summerflag:
        # 夏季作息
        if _datetime <= onworkTime(_datetime,summermorningend):
            # 夏季作息,上午请假返回上午剩余时间 + 下午班时长
            return (onworkTime(_datetime,summermorningend)-_datetime).seconds + (onworkTime(_datetime,summerafternoonend)-onworkTime(_datetime,summerafternoonstart)).seconds
        else:
            # 夏季作息,下午请假返回下午剩余时长
            return (onworkTime(_datetime, summerafternoonend) - _datetime).seconds
    else:
        # 冬季作息
        if _datetime <= onworkTime(_datetime, wintermorningend):
            # 冬季作息,上午请假返回上午剩余时间 + 下午班时长
            return (onworkTime(_datetime, wintermorningend) - _datetime).seconds + (
                        onworkTime(_datetime, winterafternoonend) - onworkTime(_datetime, winterafternoonstart)).seconds
        else:
            # 冬季作息,下午请假返回下午剩余时长
            return (onworkTime(_datetime, winterafternoonend) - _datetime).seconds

2,请假截止日期用掉的秒数

def effectiveEndSeconds(_datetime):
    '''
    计算请假截止当天的剩余有效请假时间
    :param _datetime: 请假截止当天的时间
    :return: 剩余秒
    '''

    # 判断是否是夏季作息
    summerflag = isSummer(_datetime)

    if summerflag:
        # 夏季作息
        if _datetime <= onworkTime(_datetime,summermorningend):
            # 夏季作息,上午请假返回上午请假时间
            return (_datetime - onworkTime(_datetime,summermorningstart)).seconds
        else:
            # 夏季作息,下午请假返回下午请假时长 + 上午工作时长
            return (_datetime - onworkTime(_datetime, summerafternoonstart)).seconds + (onworkTime(_datetime, summermorningend) - onworkTime(_datetime, summermorningstart)).seconds
    else:
        # 冬季作息
        if _datetime <= onworkTime(_datetime, wintermorningend):
            # 冬季作息,上午请假返回上午请假时间
            return (_datetime - onworkTime(_datetime,wintermorningstart)).seconds
        else:
            # 冬季作息,下午请假返回下午请假时长 + 上午工作时长
            return (_datetime - onworkTime(_datetime, winterafternoonstart)).seconds + (onworkTime(_datetime, wintermorningend) - onworkTime(_datetime, wintermorningstart)).seconds

3,获取有效的起始时间

def effectiveStartTime(_datetime):
    '''
    根据作息时间表获取请假有效起始时间
    :param _datetime:请假起始时间
    :return:请假有效起始时间
    '''

    # 判断传入的时间是否是夏季作息
    summerflag = isSummer(_datetime)

    if summerflag:
        # 夏季作息,上午上班前
        if _datetime <= onworkTime(_datetime, summermorningstart):
            # 夏季作息,返回夏季上午上班时间
            return onworkTime(_datetime, summermorningstart)
        # 夏季作息,下班时间后
        elif _datetime >= onworkTime(_datetime, summerafternoonend):
            # 起始时间加一
            _datetime += datetime.timedelta(days=1)
            if isSummer(_datetime):
                # 夏季作息,返回次日夏季上班时间
                return onworkTime(_datetime,summermorningstart)
            else:
                # 冬季作息,返回次日冬季上班时间
                return onworkTime(_datetime, wintermorningstart)
        # 夏季作息,午休时间
        elif _datetime in interval.Interval(onworkTime(_datetime, summermorningend),
                                            onworkTime(_datetime, summerafternoonstart)):
            # 夏季作息,午休时间返回上午班结束时间
            return onworkTime(_datetime, summermorningend)
        else:
            # 夏季作息,工作时间直接返回
            return _datetime
    else:
        # 冬季作息,上午上班前
        if _datetime >= onworkTime(_datetime, wintermorningstart):
            # 冬季作息,返回冬季上班时间
            return onworkTime(_datetime, wintermorningstart)
        # 冬季作息,下班时间后
        elif _datetime >= onworkTime(_datetime, wintermorningstart):
            # 起始时间加一
            _datetime += datetime.timedelta(days=1)
            if isSummer(_datetime):
                # 夏季作息,返回次日夏季上午上班时间
                return onworkTime(_datetime , summermorningstart)
            else:
                # 冬季作息,返回次日冬季上午上班时间
                return onworkTime(_datetime , wintermorningstart)
        # 冬季午休时间
        elif _datetime in interval.Interval(onworkTime(_datetime, wintermorningend),
                                            onworkTime(_datetime, winterafternoonstart)):
            # 返回冬季上午班结束时间
            return onworkTime(_datetime, wintermorningend)
        else:
            return _datetime

4,获取有效的截止时间

def effectiveEndTime(_datetime):
    '''
    根据作息时间表获取请假有效结束时间
    :param _datetime:请假结束时间
    :return:请假有效结束时间
    '''

    # 判断传入的时间是否是夏季作息
    summerflag = isSummer(_datetime)

    if summerflag:
        # 夏季作息,上午上班前
        if _datetime <= onworkTime(_datetime,summermorningstart):
            # 结束时间减一
            _datetime -= datetime.timedelta(days=1)
            if isSummer(_datetime):
                # 夏季作息,返回夏季下班时间
                return onworkTime(_datetime,summerafternoonend)
            else:
                # 冬季作息,返回冬季下班时间
                return onworkTime(_datetime,winterafternoonend)
        # 夏季作息,下午下班后
        elif _datetime >= onworkTime(_datetime,summerafternoonend):
            # 夏季作息,返回夏季下班时间
            return onworkTime(_datetime,summerafternoonend)
        # 夏季作息,午休时间
        elif _datetime in interval.Interval(onworkTime(_datetime,summermorningend),onworkTime(_datetime,summerafternoonstart)):
            # 夏季作息,返回夏季上午班结束时间
            return onworkTime(_datetime,summermorningend)
        else:
            # 夏季作息,上班时间直接返回
            return _datetime
    else:
        # 冬季作息,上午上班前
        if _datetime <= onworkTime(_datetime, wintermorningstart):
            # 结束时间减一
            _datetime -= datetime.timedelta(days=1)
            if isSummer(_datetime):
                # 夏季作息,返回夏季下班时间
                return onworkTime(_datetime, summerafternoonend)
            else:
                # 冬季作息,返回冬季下班时间
                return onworkTime(_datetime, winterafternoonend)
        # 冬季作息,下班时间后
        elif _datetime >= onworkTime(_datetime, winterafternoonend):
            # 冬季作息,返回冬季下班时间
            return onworkTime(_datetime, winterafternoonend)
        # 冬季作息,午休时间
        elif _datetime in interval.Interval(onworkTime(_datetime, wintermorningend),
                                            onworkTime(_datetime, winterafternoonstart)):
            # 冬季作息,返回冬季上午班结束时间
            return onworkTime(_datetime, wintermorningend)
        else:
            #冬季作息,上班时间直接返回
            return _datetime

5,获取当日的上班,休息,下班时间点

def onworkTime(_datetime,_worktime):
    '''
    获取日期时间拼接的时间
    :param _datetime:
    :param _worktime:
    :return:
    '''
    return datetime.datetime.strptime(' '.join([datetime.datetime.strftime(_datetime,'%Y-%m-%d'),_worktime]),'%Y-%m-%d %H:%M:%S')

6,判断当日是不是夏季作息

def isSummer(_date):
    '''
    判断给定参数是否是夏季作息时间
    :param _date: 给定的时间
    :return: 是返回 True,否返会 False
    '''
    date = toDateTime(_date)
    if date in summer:
        return True
    else:
        return False

7,尝试将主函数的传入参数转换为时间

def toDateTime(_date):
    '''
    将输入时间或者时间字符串转为时间
    :param _date: 时间或时间字符串
    :return: 返回时间
    '''
    # 日期时间直接返回
    if isinstance(_date, datetime.datetime):
        return _date
    # 尝试将字符串转化为日期时间
    else:
        try:
            date = datetime.datetime.strptime(_date,'%Y-%m-%d %H:%M:%S')
        except:
            # 异常直接返回 '9999-12-31 23:59:59'
            return datetime.datetime.strptime('9999-12-31 23:59:59','%Y-%m-%d %H:%M:%S')
        else:
            return date

8,测试结果

if __name__ == '__main__':
    sdate = '2021-04-01 09:00:00'
    edate = '2021-11-02 08:00:00'
    print(sdate)
    print(edate)
    print(effectiveStartTime(toDateTime(sdate)))
    print(effectiveEndTime(toDateTime(edate)))
    print(leaveBillTime(sdate,edate))

2021-04-01 09:00:00
2021-11-02 08:00:00
2021-04-01 08:30:00
2021-11-01 17:30:00
(215.0, 5306400)
完整的代码下载地址

完整代码下载

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值