参考资料:https://ask.csdn.net/questions/390993
测试数据:工号+姓名+打卡时间(只要打卡一次就记录一次时间)
测试文件格式:CSV或txt
12345,zhangsan,2018-12-05 01:57
12345,zhangsan,2018-12-05 01:57
12345,zhangsan,2018-12-05 01:58
12345,zhangsan,2018-12-05 01:58
12345,zhangsan,2018-12-05 01:59
1234,zhangsan,2018-12-05 01:59
12345,zhangsan,2018-12-05 02:02
12345,zhangsan,2018-12-05 02:02
12345,zhangsan,2018-12-05 02:03
12345,zhangsan,2018-12-05 02:03
1000,zhangsan,2018-12-05 02:04
1000,zhangsan,2018-12-05 02:05
1000,zhangsan,2018-12-05 02:05
1000,zhangsan,2018-12-05 02:05
1000,zhangsan,2018-12-05 02:06
1005,zhangsan,2018-12-05 02:06
1000,zhangsan,2018-12-05 02:06
1007,zhangsan,2018-12-05 02:07
1000,zhangsan,2018-12-05 02:17
1000,zhangsan,2018-12-05 02:17
1000,zhangsan,2018-12-05 02:18
1002,yang,2018-12-05 02:19
1002,yang,2018-12-05 02:19
1002,yang,2018-12-05 02:19
1002,yang,2018-12-05 02:20
1004,yang,2018-12-05 02:29
1002,yang,2018-12-05 02:30
1002,yang,2018-12-05 03:00
1002,yang,2018-12-05 03:01
1002,yang,2018-12-05 03:05
1004,yang,2018-12-05 03:05
12345,zhangsan,2018-12-05 02:03
代码实现:
效果:
第一步:输入考勤文件路径,如 c:\\2018-12-05.txt,返回结果list,此list内容格式如: 工号+姓名+最早打卡时间+最晚打卡时间。
第二部:将上述list写入CSV文件(可选操作)
Employee类
public class Employee implements Comparator<Employee> {
//想直接利用List的API来排序,就要实现这个接口
public String getStaffId() {
return staffId;
}
public void setStaffId(String staffId) {
this.staffId = staffId;
}
public String getCheckTime() {
return checkTime;
}
public void setCheckTime(String checkTime) {
this.checkTime = checkTime;
}
public String getStaffName() {
return staffName;
}
public void setStaffName(String staffName) {
this.staffName = staffName;
}
private String staffId;
private String staffName;
private String checkTime;
//比较本对象和参数是否为同一天,这一个方法只是在一个打卡文件里有几天的打卡记录时才使用
//但是一般一个文件对应一天的记录,所以本例中没有使用
public boolean isSameDay(Employee attendance) {
return this.checkTime.split(" ")[0].equals(attendance.getCheckTime().split(" ")[0]);
}
//按打卡时间排序的逻辑
@Override
public int compare(Employee employee, Employee t1) {
Date date1 = null;
Date date2 = null;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
try {
date1 = formatter.parse(employee.getCheckTime());
date2 = formatter.parse(t1.getCheckTime());
} catch (ParseException e) {
e.printStackTrace();
}
return (int) (date1.getTime() - date2.getTime());
}
}
private static List<String> generateList(String csvPath) {
List<String> resultList = new ArrayList<>(); //返回的结果
Map<String, List<Employee>> map = new HashMap<>();
List<Employee> employeeList = new ArrayList<>(); //这个list包含了全部的数据
BufferedReader bufferedReader = null;
//第一步:按行读取全部打卡CSV源数据到employeeList中
try {
bufferedReader = new BufferedReader(new FileReader(csvPath));
String line = null;
Employee employee;
while ((line = bufferedReader.readLine()) != null) {
String employeeData[] = line.split(",");
employee = new Employee();
employee.setStaffId(employeeData[0]);
employee.setStaffName(employeeData[1]);
employee.setCheckTime(employeeData[2]);
employeeList.add(employee);
}
//第二步:遍历employeeList,不同的工号人员分类
String staffId = "";
for (Employee employee1 : employeeList) {
staffId = employee1.getStaffId();
employeeList = map.get(staffId); //根据工号找到其所有的打卡时间
if (employeeList == null) {
employeeList = new ArrayList<>();
}
employeeList.add(employee1); //给该工号添加一条时间记录
map.put(staffId, employeeList); //将该记录添加到map
}
//第三部:将map中的数据进行整理分析,排序打卡时间
for (Map.Entry<String, List<Employee>> entry : map.entrySet()) {
StringBuffer stringBuffer = new StringBuffer();
employeeList = entry.getValue(); //一个员工的所有打卡时间列表
employeeList.sort(new Employee()); //根据打卡时间排序,得到按时间从小到大的有序列表
employee = employeeList.get(0);//得到第一个有序列表的第一个打卡时间(最早打卡时间)
//得到最早的打卡时间(即排在第一个的节点)
stringBuffer.append(employee.getStaffId() + "," + employee.getStaffName() + "," + employee.getCheckTime());
//(遍历整个有序时间列表)得到最晚的打卡时间
for (Employee employee1 : employeeList) {
//本例中下面的if不是必要的,因为一个文件对应一天的打卡记录
//只需要遍历到最后的日期就行
//如果一个CSV文件里面有不同的日期,才需要在这里面判断
// if (!employee.isSameDay(employee1)) {
// System.out.println(employee.getCheckTime().split(" ")[1]);
// System.out.print("员工号:" + employee1.getStaffId() + "\t" + employee1.getCheckTime().split(" ")[0] +
// "\t最早考勤时间:" + employee1.getCheckTime().split(" ")[1] + "\t最晚考勤时间:");
// }
//建议每天的打卡记录保存为不同的CSV文件
employee = employee1;
}
//System.out.println(employee.getCheckTime().split(" ")[1] + "\n");
stringBuffer.append("," + employee.getCheckTime());
resultList.add(stringBuffer.toString());
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
bufferedReader.close();
map.clear();
employeeList.clear();
} catch (IOException e) {
e.printStackTrace();
}
}
return resultList;
}
上面的方法已经能得到结果了,以下的内容不是必须的。
目的:将上述的List结果写入CSV文件
/**
*
* @param list 上述方法返回的结果list
* @param path 目标文件保存地址
*/
private static void analyzeAndCreate(List<String> list, String path) {
File file = new File(path);
//如果是目录,记得mkdirs
try {
if (!file.exists())
file.createNewFile();
else
file.delete();
StringBuffer buffer;
FileOutputStream outputStream = new FileOutputStream(file, true);
buffer = new StringBuffer("工号,姓名,最早打卡时间,最晚打卡时间\r\n");
outputStream.write(buffer.toString().getBytes("gbk"));
for (String string : list) {
buffer = new StringBuffer(string);
buffer.append("\r\n");
outputStream.write(buffer.toString().getBytes("gbk"));
}
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
main函数
public static void main(String[] args) {
System.out.println("hello world");
List<String> resultList = generateList("c:\\2018-12-05.csv"); //txt文件也行
for (String s : resultList) {
System.out.println(s);
}
analyzeAndCreate(resultList, "c:\\2018-12-05分析.csv"); //打开这个文件就看到了统计结果
}
打开CSV文件:
注意:我是在Android 5.1下使用的上述java方法,但是报错(API 24及以上不会):java.lang.NoSuchMethodError: No interface method sort(Ljava/util/Comparator;),这是由employeeList.sort(new Employee());这一句引起的。
如果你遇到这个错误,解决办法之一:就是将employeeList.sort(new Employee());替换成
Collections.sort(employeeList, new Comparator<Employee>() { //List排序
@Override
public int compare(Employee o1, Employee o2) {
Date date1 = null;
Date date2 = null;
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
try {
date1 = formatter.parse(o1.getCheckTime());
date2 = formatter.parse(o2.getCheckTime());
} catch (ParseException e) {
e.printStackTrace();
}
return (int) (date1.getTime() - date2.getTime());
}
});
参考链接:https://blog.csdn.net/qq_31371757/article/details/84837464