扔到这又快一礼拜了,回来更新下吧,写这篇博客的原因是因为单位是传统的金融行业,条条框框很多,各种的流程让你走到头发都消失了。所要吐槽的就是每个月都要进行打卡考勤,打卡还没完还需要在一个系统上根据项目组的人数,按本月的投产日期(该投产日期还不固定)的上一周周一开始计算,到下个月投产日期的上上周的周日截至,计算之间的工作日天数(要减去法定节假日和加上休息日变更为工作日的天数),这个还不算完还有一个任务分值的东东,范围在105-113之间(一般都是取113这个值),根据这三者之间的关系计算出下个月需要报工拆分多少个任务。是不是绕晕了反正我是晕了,要知道我只拆分了几次就要发狂了,而这个项目确实实打实的运行了六年之久,很难想象他们是怎么熬过来的,每次手工要做这个反复的工作。

好了不吐槽了,本次要实现的就是编写一个Python工具,根据给定报工人数(worker)、工作日天数(workdays)、任务分值(113)、任务系数(coefficient),计算任务数(jobs)。公式如下:coefficient = 113 jobs / (int(work_days) worker)需要设计的就是计算两个日期区间内所有的工作日,需要减去法定节假日以及如果休息日被调整为工作日也需要进行添加,这个也是核心算法。第二个要设计的就是本次拆分任务的工作后期要生成excel文件(本次暂不涉及,后续补充)我们要计算给定日期计算下个月或者上个月等月份的任务数,并且要计算出指定日期月份的所有天数,保存到excel中便于开展后续工作。第三个就是计算报工数量,说了那么多开始上代码吧,里边代码注释还是比较详细的的,为了这该死的记性也是拼了。

# _*_ coding:utf-8 _*_
# Author: dai bing
# Date: 2020/12/13 22:48
# Scripts: calcworkday.py
# Version:v0.2
# Desc: 给定两个日期区间,计算区间内的工作日
# 需要排除法定节假日以及统计休息日内调整为工作日内的天数
# 给定人数计算出需要多少个任务满足报工需求
#
import calendar
import datetime
import time
class Tasks:
weeks = ['星期一', '星期二', '星期三', '星期四', '星期五', '星期六', '星期天']
pattern = "%Y-%m-%d"
def __init__(self):
super(Tasks, self).__init__()
self._person = None
self._start_date = None
self._end_date = None
self._statutory_holidays = None
self._non_rest_days = None
@property
def person(self):
return self._person
@person.setter
def person(self, value):
self._person = value
@property
def startDate(self):
return self._start_date
@startDate.setter
def startDate(self, value):
sdate = None
try:
if isinstance(value, str):
sdate = datetime.datetime.strptime(value, self.pattern)
else:
raise Exception
except Exception as e:
print("输入值{}类型为{},需要输入日期型字符串或日期型数组.".format(value, type(value)))
print(e)
exit(11)
self._start_date = sdate
@property
def endDate(self):
return self._end_date
@endDate.setter
def endDate(self, value):
edate = None
try:
if isinstance(value, str):
edate = datetime.datetime.strptime(value, self.pattern)
else:
raise Exception
except Exception as e:
print("输入值{}类型为{},需要输入日期型字符串或日期型数组.".format(value, type(value)))
print(e)
exit(12)
self._end_date = edate
@property
def statutoryHolidays(self):
return self._statutory_holidays
@statutoryHolidays.setter
def statutoryHolidays(self, value):
change_statutory_holidays = []
try:
if isinstance(value, list):
for sholiday in value:
# print(datetime.datetime.strptime(sholiday, pattern))
change_statutory_holidays.append(datetime.datetime.strptime(sholiday, self.pattern))
elif isinstance(value, str):
change_statutory_holidays.append(datetime.datetime.strptime(value, self.pattern))
except ValueError:
print("输入值{}类型为{},需要输入日期型字符串或日期型数组.".format(value, type(value)))
exit(13)
self._statutory_holidays = change_statutory_holidays
@property
def nonRestDay(self):
return self._non_rest_days
@nonRestDay.setter
def nonRestDay(self, value):
change_work_day = []
pattern = "%Y-%m-%d"
try:
if isinstance(value, list):
for non_work_day in value:
change_work_day.append(datetime.datetime.strptime(non_work_day, pattern))
elif isinstance(value, str):
change_work_day.append(datetime.datetime.strptime(value, pattern))
except TypeError:
print("输入值{}类型为{},需要输入日期型字符串或日期型数组.".format(value, type(value)))
exit(14)
self._non_rest_days = change_work_day
# 计算指定日期区间内的工作日
# statutory_h排除法定节假日
# work_do休息日调休变更为工作日
def getWorkDay(self, statutory_h, work_do):
"""
给定日期区间,计算区间内的工作日,并减去区间内的法定节假日和调休工作日
:param statutory_h: 需要排除的法定节假日,参数为datetime的集合
:param work_do: 休息日变更为工作日的日期,参数为datetime的集合
:return: 返回一个yield对象
"""
day_off = 5, 6
# print(day_off)
days_work = [x for x in range(7) if x not in day_off]
# 排除法定节假日
statutory_holidays = statutory_h
# 增加调休工作日
non_rest_days = work_do
# print("statutory_holidays: ", len(statutory_holidays))
# print("work_day_off:", len(work_day_off))
tag_date = self.startDate
flag = 0
while True:
if tag_date > self.endDate:
break
if tag_date.weekday() in days_work and tag_date not in statutory_holidays or tag_date in non_rest_days:
yield tag_date
tag_date += datetime.timedelta(days=1)
def getjobs(self, work_days, worker):
"""
计算要报工的任务数,计算任务公式:系数 = 任务分值*任务数/报工工作日/报工人数
:param work_days: 工作日天数
:param worker: 需要报工人数
:return: 所需报工的任务数
"""
jobs = 1
job_month = self.add_months(self.startDate).month
while True:
# 113 * jobs/40/6
coefficient = 113 * jobs / (int(work_days) * worker)
jobs += 1
if coefficient > 4:
if coefficient < 5:
print("[{}]{}月份共有{}位需要报工人员,需要{}个任务拆分进行报工。"
.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
job_month, self.person, jobs))
break
def add_months(self, source_date, months=1):
"""
获取指定月份几个月之后或之前的月份及日期
:param source_date: 起始日期
:param months: 月份跨度
:return: 返回起始日期source_date与months相加之后的日期,格式为datetime.date
"""
month = source_date.month - 1 + months
year = source_date.year + month // 12
month = month % 12 + 1
day = min(source_date.day, calendar.monthrange(year, month)[1])
print("monthrange:",calendar.monthrange(year, month))
return datetime.date(year, month, day)
def daysCount(self):
"""工作日统计,返回数字"""
return len(list(self.getWorkDay(self.statutoryHolidays, self.nonRestDay)))
if __name__ == "__main__":
print(__name__)