Python计算两日期之间排除节假日与非上班时间的工作时间

  • 前言
  • 一、基本思路
  • 二、代码示例
  • 总结

文章目录

  • 前言
  • 一、基本思路
  • 二、代码示例
  • 总结

前言

工作中遇见需要写UDF计算事项办理时间的需求,事项申请和办结由于在线上,可能不在办理时间内,因此要求排除节假日与工作日的非工作时间(午休时间、上班前与下班后的时间),在次做下记录。


一、基本思路

首先需要获取法定节假日,这里参考了另一篇从万年历爬取全年法定节假日时间的文章:
Python获取全年法定节假日时间
文章中已经很详细地叙述了从万年历爬取节假日日期的方法,逻辑也比较简明,有具体节假日爬取需求可以参考一下。
代码示例:

# -*- coding: utf-8 -*-
import requests
from lxml import etreedef get_holiday(year):"""Params:year 四位数年份字符串""""""页面解析"""url = 'https://wannianrili.51240.com/ajax/'headers = {'Host': 'wannianrili.51240.com','Connection': 'keep-alive','User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36','Accept': '*/*','Sec-Fetch-Site': 'same-origin','Sec-Fetch-Mode': 'cors','Sec-Fetch-Dest': 'empty','Referer': 'https://wannianrili.51240.com/','Accept-Encoding': 'gzip, deflate, br','Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',}list_holiday = []# 生成月份列表dateList = [year + '-' + '%02d' % i for i in range(1, 13)]for year_month in dateList:s = requests.session()url = 'https://wannianrili.51240.com/ajax/'payload = {'q': year_month}response = s.get(url, headers=headers, params=payload)element = etree.HTML(response.text)html = element.xpath('//div[@class="wnrl_riqi"]')for _element in html:# 获取节点属性item = _element.xpath('./a')[0].attribif 'class' in item:if item['class'] == 'wnrl_riqi_xiu' or item['class'] == 'wnrl_riqi_mo':_span = _element.xpath('.//text()')list_holiday.append(year_month + '-' + _span[0])return list_holiday

然而因为这个网站时不时会崩,因此可以考虑稳妥的方式,就是使用chinesecalendar这个库,其中is_holiday方法可以判断法定节假日。
代码示例:

# -*- coding: utf-8 -*-from chinese_calendar import is_holiday
from datetime import datedef get_holiday(year):list_holiday=[]year=int(year)for month in range(1,13):for day in range(1,32):try:dt=date(year,month,day)except:breakif is_holiday(dt):list_holiday.append('{}-{:02d}-{:02d}'.format(year,month,day))return list_holiday

在获得了节假日期后,就需要对开始时间与办结时间做对应的精准化判断,判断逻辑上略显繁琐但也比较简单,计算主要是使用datetime库中的timedelta,其实如果常用的话可以模块化一下流程中的日期处理方法,我这里写的比较糙。
我这边的案例口径是只将工作日中08:30-12:00,14:00-18:00的时间纳入计算,时间参数的格式需要是“YYYY-MM-DD HH24:MI:SS”。

二、代码示例

总体代码示例:

# -*- coding: utf-8 -*-from chinese_calendar import is_holiday
from datetime import date
from datetime import datetime
from datetime import timedeltadef get_holiday(year):list_holiday=[]year=int(year)for month in range(1,13):for day in range(1,32):try:dt=date(year,month,day)except:breakif is_holiday(dt):list_holiday.append('{}-{:02d}-{:02d}'.format(year,month,day))return list_holidaydef datediff_no_holiday(start,end):"""Params:start:开始时间end:结束时间'yyyy-mm-dd hh24:mi:ss'格式字符串"""if start>=end or not start or not end:return 0if start[:4]==end[:4]:list_holiday=get_holiday(end[:4])else:list_holiday=[]for year in range(int(start[:4]),int(end[:4])+1):list_holiday=list_holiday+get_holiday(str(year))list_holiday=list( map(lambda x : datetime.strptime(x,'%Y-%m-%d'), list_holiday) )result=0list_start=start.split(' ')start=datetime.strptime(start, '%Y-%m-%d %H:%M:%S')start_d=datetime.strptime(list_start[0],'%Y-%m-%d')list_end=end.split(' ')end=datetime.strptime(end, '%Y-%m-%d %H:%M:%S')end_d=datetime.strptime(list_end[0],'%Y-%m-%d')#首先判断结束时间是否在工作时间内,如果早于当天工作时间则转换为上班时间,如果大于则转换为后一天上班时间if list_end[1]>'18:00:00':end=end_d+timedelta(hours=18)if list_end[1]<'08:30:00':end=end_d+timedelta(hours=8, minutes=30)list_end[1]='08:30:00'#同理判断开始时间,如果大于则转换为后一天上班时间if list_start[1]>'18:00:00':start_d+=timedelta(days=1)start=start_d+timedelta(hours=8, minutes=30)list_start[1]='08:30:00'#判断是否在节假日(包括不补班的周末)中,如果是则转入下一天进行循环判断if start_d in list_holiday:while start_d in list_holiday:start_d+=timedelta(days=1)start=start_d+timedelta(hours=8, minutes=30)list_start[1]='08:30:00'if end_d in list_holiday:while end_d in list_holiday:end_d+=timedelta(days=1)end=end_d+timedelta(hours=8, minutes=30)list_end[1]='08:30:00'#判断开始时间,如果早于当天工作时间则转换为当天上班时间if list_start[1]<'08:30:00':start=start_d+timedelta(hours=8, minutes=30)#剔除12点到14点的午休时间if '12:00:00'<list_start[1]<'14:00:00':start=start_d+timedelta(hours=14)list_start[1]='14:00:00'if start>=end:return 0#如果开始与结束在同一日期里if start_d==end_d:result=(end-start).secondsif list_start[1]<='12:00:00':  #如果开始时间在上午if list_end[1]>='14:00:00':result-=7200if '12:00:00'<list_end[1]<'14:00:00':result-=(end-(end_d+timedelta(hours=12))).seconds#如果开始与结束不在同一日期里,排除中间可能存在的节假日else:if list_start[1]<='12:00:00':result-=7200result+=(start_d+timedelta(hours=18)-start).secondsstart_d+=timedelta(days=1) #while start_d<end_d:if start_d not in list_holiday:result+=27000  #每日工时7.5*3600秒start_d+=timedelta(days=1)result+=(end-(end_d+timedelta(hours=8, minutes=30))).secondsif list_end[1]>='14:00:00':result-=7200elif '12:00:00'<list_end[1]<'14:00:00':result-=(end-(end_d+timedelta(hours=12))).secondsreturn result if result>0 else 0"""返回相差的秒数"""if __name__ == '__main__':start='2020-09-30 13:00:00'end='2020-10-09 15:00:00'hours=datediff_no_holiday(start,end)print(hours/3600,'小时')

结果为 8.5 小时

总结

呱。

Python计算两日期之间排除节假日与非上班时间的工作时间相关推荐

  1. 计算两日期之间差多少天----日期格式为:yyyy-mm-dd

    计算两日期之间差多少天 日期格式为yyyy-mm-dd //计算日期差值的方法: //计算日期差值的方法: function getDaysBetween(dateString1, dateStrin ...

  2. 关于计算两日期之间经过多少天的超巧妙算法(转载)

    转载地址:https://www.cnblogs.com/cndccm/p/11974754.html 原创地址:https://blog.csdn.net/chinaeran/article/det ...

  3. java 跨年 周计算公式_如何跨年计算 两日期之间相隔的周数 with java8 time API

    ===============================2016年9月版 分割线======================================== 之前版本的我太simple了.. ...

  4. java:通过Calendar类正确计算两日期之间的间隔

    在开发Android应用时偶然需要用到一个提示用户已用天数的功能,从实现上来看无非就是持久化存入用户第一次使用应用的时间firstTime(通过SharedPreferences .xml.sqlit ...

  5. 通过Calendar类正确计算两日期之间的间隔

    在开发时需要用到一个提示用户已用天数的功能,从实现上来看无非就是持久化存入用户第一次使用应用的时间firstTime(通过SharedPreferences .xml.sqlite等),当用户再次使用 ...

  6. python时间计算_python计算两日期之间工作日时长

    1. 原因:使用dateutil的rrule时,计算速度比较慢 def axx(): from dateutil import rrule received_time = datetime.datet ...

  7. 【excel】利用NETWORKDAYS.INTL函数计算两日期之间的工作日时间

    语法 NETWORKDAYS.INTL(start_date, end_date, [weekend], [holidays]) start_date 和 end_date:必需,要计算其差值的日期. ...

  8. MySql计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数

    计算两日期时间之间相差的天数,秒数,分钟数,周数,小时数,这里主要分享的是通过MySql内置的函数 TimeStampDiff() 实现. 函数 TimeStampDiff() 是MySQL本身提供的 ...

  9. Oracle 计算两日期间隔月数

    Oracle 计算两日期之间月数 实际应用中,有时候会计算两日期间隔天数.月数.如直接相减,可能会出问题,如: select 202110-202106 from dual; 结果为:4 看似正确,但 ...

最新文章

  1. 百变应用场景下,优酷基于图执行引擎的算法服务框架筑造之路!
  2. stn专线和otn有什么区别_专线与干线运输的区别是什么?
  3. 典型问题分析(十五)
  4. android 沉浸式导航栏
  5. 基于深度学习的图像修补/完整方法分析
  6. stm32驱动_STM32直流电机启动(一)驱动电路的介绍
  7. 从零开始实现数据结构(二) 有序数组
  8. 【 全干货 】5 分钟带你看懂 Docker ! 1
  9. paip.windows io监控总结
  10. Docker安装Redis 6.2.6的3主3从集群和集群的扩缩容操作
  11. 室外无线AP覆盖解决方案
  12. opendevops_codo项目研究
  13. 那些一出口就很Low的话
  14. Percentile Ranks Aggregation
  15. crossed the “t‘s“, dotted the “i‘s“, grouted the tiles是什么意思?
  16. Sigmastar平台_锐化调试思路
  17. actor 模型原理 (一)
  18. nginxpcmobile
  19. w7怎么修改计算机用户名,教您电脑用户名怎么修改
  20. 纯css控制文字显示隐藏

热门文章

  1. Standard 1.1.x VM与Standard VM的区别
  2. 蓝牙协议分析工具Frontline 15安装与使用
  3. 三种定时器Timer的使用
  4. windows2008r2 sp1 官方杀毒软件Microsoft Security Essentials(mse)_php_sir_新浪博客
  5. TRACERT 跟踪路由命令
  6. 100天精通Python(基础篇)——第2天:入门必备
  7. RabbitMQ下载安装(windows版本+linux版本合集)
  8. NeurIPS 2022 | 开放域检测新方法DetCLIP,推理效率提升20倍
  9. 数字IC设计——功耗分析
  10. 题目:P3056 [USACO12NOV]Clumsy Cows S