根据使用生物识别设备生成的CSV文件计算出勤率



首先,我是Python的初学者,这是我第一次为个人项目编写脚本,所以请温和回答。

输入

我有一个未排序的CSV文件,其中包含给定月份所有员工的登录时间,看起来像:

2020年2月13日09:43
2020年2月12日10:26
20200年2月10日12:12
10200年3月13日18:22
1020年3月12日18:23
13203年3月3日09:51
122020年3月30日10:38
19200年3日12时02
132003年3日18时28
12:03年3

其中第一列是员工id,第二列是登录/注销时间。

我想知道从文件中读取登录时间并计算的最佳/最有效的方法:

输出

基本:
1。员工在办公室的天数
2。员工每天的总工作时间

Employee ID - xxxx
Date        Duration  
DD/MM/YY    hh:mm:ss
DD/MM/YY    hh:mm:ss
DD/MM/YY    hh:mm:ss
Total No. of Working Days in this month: 

高级:
计算哪些日子是星期天,并将这些日子添加到当前的考勤中
更高级:
与某个地区的在线谷歌日历进行比较,以查找该地区当月的假期,并将那些假期添加到其考勤中

我的逻辑:

  1. 读取CSV文件,提取登录时间并将其保存在排序列表中。这将创建一个列表列表,如下所示:
[['10', '03/02/2020 12:12'],['10', '03/03/2020 12:02'], ['10', '03/06/2020 15:12'], ['10', '03/07/2020 16:18'], ['10', '03/08/2020 11:04'], ['10', '03/08/2020 11:05'], ['10', '03/09/2020 11:27'], ['10', '03/10/2020 17:06'], ['10', '03/11/2020 22:13'], ['10', '03/12/2020 11:13'], ['10', '03/13/2020 11:57'], ['10', '03/14/2020 11:29'], ['10', '03/16/2020 10:32'], ['10', '03/17/2020 17:37'], ['10', '03/18/2020 12:24'], ['10', '03/19/2020 15:38'], ['10', '03/19/2020 15:45'], ['10', '03/20/2020 15:26']]
  1. 将此列表转换为排序字典,以便将员工的所有登录时间一起保存在列表中。看起来像:
{'10':['03/02/2020 12:12','03/02/2020 15:38','03/08/2020 11:05'],  
'12':['03/03/2020 11:27','03/03/2020 12:02','03/03/2020 18:29'],  
'13':['03/16/2020 10:32','03/16/2020 11:57','03/16/2020 19:04']}

等等…

其中,字典的"键"是员工ID,"值"是按日期排序的所有登录/注销时间的列表

  1. 对于每个员工ID,每天使用datetime模块的timedelta功能计算第一次登录时间和最后一次注销时间之间的时间差(肯定会有多个条目(

  2. 创建一个excel文件,看起来像上面显示的预期输出

问题

看起来是一项非常简单明了的任务,但。。。

我一直在尝试将列表列表合并到一个合适的字典中,以员工id为关键字,以他们所有登录时间的列表为值。试图在谷歌上搜索一个可能的解决方案让我https://thispointer.com/python-how-to-convert-a-list-to-dictionary/.但这对我的问题没有帮助,因为我正试图从同一个列表中提取非常具体的信息。

在stackoverflow上找不到类似的东西,所以我发布了一个新问题。

同样,我是编程新手,所以请让我知道我解决这个问题的逻辑是否合理,或者我应该尝试不同的方法。

附言:我看过熊猫,但在这一点上,对于这样一项简单的任务,似乎没有必要从头开始学习
此外,下一步,计算时差可能比我想象的要困难,因此欢迎提供任何帮助
此外,我并不是要求为自己编写代码。我想学习这种优美的语言,这样我就可以变得更好,轻松地创建这样的脚本。

如果你能走到这一步,谢谢你抽出时间!你让世界变得更美好:(

我想你只是在寻找一种将列表列表转换为dict的方法,试试这个:

from collections import defaultdict
import pprint
l = [['10', '03/02/2020 12:12'],['10', '03/03/2020 12:02'], ['10', '03/06/2020 15:12'], ['10', '03/07/2020 16:18'], ['10', '03/08/2020 11:04'], ['10', '03/08/2020 11:05'], ['10', '03/09/2020 11:27'], ['10', '03/10/2020 17:06'], ['10', '03/11/2020 22:13'], ['10', '03/12/2020 11:13'], ['10', '03/13/2020 11:57'], ['10', '03/14/2020 11:29'], ['10', '03/16/2020 10:32'], ['10', '03/17/2020 17:37'], ['10', '03/18/2020 12:24'], ['10', '03/19/2020 15:38'], ['10', '03/19/2020 15:45'], ['10', '03/20/2020 15:26'], ['11', '03/19/2020 15:45'], ['11', '03/20/2020 15:26'], ['12', '03/19/2020 15:45'], ['12', '03/20/2020 15:26']]
datesByEmployee = defaultdict(list)
for ll in l:
datesByEmployee[ll[0]].append(ll[1])
pp = pprint.PrettyPrinter(indent=4)
pp.pprint(dict(datesByEmployee))

这给了你:

{   '10': [   '03/02/2020 12:12',
'03/03/2020 12:02',
[...]],
'11': ['03/19/2020 15:45', '03/20/2020 15:26'],
'12': ['03/19/2020 15:45', '03/20/2020 15:26']}

下面是employee(ID:13(的一个输出示例,我的脚本创建的文件名为出席ID-13 2020-04-05.txt

请注意我的脚本到目前为止的两个导入限制
1(它创建的是.txt文件,而不是.xlsx
2(它只需要最短的白天时间,并减去当天的最长时间

限制2还意味着,当某人在某一天(即3月2日(登录并在第二天(3月3日(注销时,在输出文件的持续时间列中,您会发现"当天没有注销"。此外,如果一个人一天多次登录和注销,即休息,这些时间将被忽略
然而,这将是单独的问题,这是解决的一部分

输出文件示例: 出席ID-13 2020-04-05.txt

员工ID-13

日期持续时间
2020年3月2日8:39:0
20200年3月3日8:37:0

我的代码/熊猫解决方案:

#!/usr/bin/env python3
import pandas as pd
from pathlib import Path
import numpy as np
import datetime
from math import floor
def time_to_delat(t):
"""Convert datetime.time object with hour and minute to datetime.timedelta object"""
dt = datetime.timedelta(hours=t.hour, minutes=t.minute)
return dt
def trans_form_tostring(dt):
hours = dt.seconds//3600
minutes = (dt.seconds//60)%60
seconds = dt.seconds%60
return f"{hours}:{minutes}:{seconds}"
def main():
# set path to csv
path_to_csv = Path("C:/Test/tmp_csv.csv")
# set names for the columns
header = ['ID','Datetime']
# read the csv as pandas dataframe
df = pd.read_csv(path_to_csv, names = header,parse_dates=True)
# Convert the column 'Date' to a datetime object
df['Datetime'] = pd.to_datetime(df['Datetime'])
df['Date'] = df['Datetime'].dt.date
df['Time'] = df['Datetime'].dt.time
for ID in df.ID.unique():
# Iterate over every unique ID of employee and Filter for a single ID
one_employee = df[df['ID']==ID].sort_values(by='Date')
# Get the earliest start time of a day and the latest time of a day
start_per_day = one_employee.groupby('Date')['Time'].min()
end_per_day = one_employee.groupby('Date')['Time'].max()
# Convert array of datetime.time objects to array of datetime.timedelta objects
start_per_day_dt = np.array([time_to_delat(x) for x in start_per_day])
end_per_day_dt = np.array([time_to_delat(x) for x in end_per_day])
# get the duration for a single day
delta_per_day = [trans_form_tostring(x) for x in (end_per_day_dt - start_per_day_dt)]
# Create an empty list dates for the attendance
attended_days = []
for i,working_day in enumerate(one_employee.Date.unique()):
if delta_per_day[i] == "0:0:0":
delta_per_day[i] = "No Logout for this day"
day = working_day.strftime("%d/%m/%Y")
attended_days.append(f"{day}t{delta_per_day[i]}")
create_excel_output(ID,attended_days,Path("C:/Test"))
def create_excel_output(ID, dates,outpath=None):
protocol_file = f"Attendance of ID-{ID} {datetime.date.today()}.txt"
if outpath is not None:
protocol_file = outpath / f"Attendance of ID-{ID} {datetime.date.today()}.txt"
employee = f"Employee ID - {ID}"
with open(protocol_file,'w') as txt:
txt.write(employee+"nn")
txt.write("DatetDurationn")
for line in dates:
txt.write(line)
txt.write("n")
if __name__ == '__main__':
main()

最新更新