数据库按周班参数计算年月日进行数据处理--------工具类设计
项目的大概情况是通过周班的人员,计算出年月日排班的人员,前台展示从今天开始往后一个月,后台展示当前月1号开始,并且是可以根据传入月份进行计算。
前后台展示的数据范围不同,要求也不同。
通过已排班的列表可以筛选出可选周班的人数,这个比较简单,问题是我如何通过周几计算出是几月几号呢,并且兼容前后台不同的数据需求?
解决过程:
我首先想到的是通过日历类去操作,但是也只能是操作年月日。问题转换为如何通过周几计算年月日。
既然要做到兼容,那么肯定要考虑代码的重复部分,初步确定写一个供自己使用的工具类,项目里没有相关的工具类,就算是有,在不清楚别人设计工具类的基础上最好不要使用,不方便后期的排查工作。
设计:
首先先放上我可能会用到的方法。 方便后期需要了直接使用。
/**
* 获取距离月底多少天
*/
public static int getDaysOfMonth(Date date) {
Calendar c = Calendar.getInstance();
int d = c.getActualMaximum(Calendar.DAY_OF_MONTH);
int now = c.get(Calendar.DAY_OF_MONTH);
return d - now;
}
/**
* 获取指定年月的天数
*/
public static int getAllDayOfMonth(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
return calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
}
那么到底如何通过周几计算出年月日呢? 我在群里询问过同行,有大佬告诉我古代算法可以实现,但是我在网上没有找到相关资料。
自己想办法处理一下。我们把思路换一下。如果现在通过年月日计算周几还是比较容易计算的。直接贴出方法。
/**
* 日期转换对应的数字表示的星期
*/
public static String dateToWeek(String datetime) throws java.text.ParseException {
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd");
String[] weekDays = {"7", "1", "2", "3", "4", "5", "6"};
Calendar cal = Calendar.getInstance(); // 获得一个日历
Date datet = null;
datet = (Date) f.parse(datetime);
cal.setTime(datet);
int w = cal.get(Calendar.DAY_OF_WEEK) - 1; // 指示一个星期中的某天。
if (w < 0)
w = 0;
return weekDays[w];
}
现在的问题是如何倒过来通过2拿到1呢?
我的思路是通过今天对应的年月日,计算出对应的周几。既然是通过周班计算的,那么我可以从今天开始计算是周几。
通过时间戳去计算后面的年月日,存到map里面,key为周几,对应上面方法中的数字,value为年月日。
先贴上代码##############################
/**
* 根据星期拿出对应的年月日,实时。拿一周的。
*/
public static String getDay(Integer dayType) throws ParseException {
// key为星期,value为年月日字符串
HashMap<String, String> map = new HashMap<>();
Date date = new Date();①
DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
String dayO = format.format(date);
String dateToWeek = dateToWeek(dayO);
map.put(dateToWeek, dayO);②
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000))), format.format(new Date(date.getTime() + 86400000)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 2))), format.format(new Date(date.getTime() + 86400000 * 2)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 3))), format.format(new Date(date.getTime() + 86400000 * 3)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 4))), format.format(new Date(date.getTime() + 86400000 * 4)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 5))), format.format(new Date(date.getTime() + 86400000 * 5)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 6))), format.format(new Date(date.getTime() + 86400000 * 6)));
return map.get(dayType.toString());
}
解释:
①代表我是那的今天对应的年月日。
②表示我拿进行的年月日通过上面转换周几的方法当做key,年月日对应的字符串为value。
因为一天的时间戳是86400000,往后推一周的数据存到Map中。
这样设计,我可以直接通过传进来的周几key拿到一周的value年月日。只是一周的!!!
############################################################################################
设计到这里,问题可以得到初步的解决,通过周班计算出从当前开始未来一周对应的年月日。
随之而来的是后面的问题,需要的数据并不是只有一周,而是从今天开始当月全部的,那么我需要考虑后面剩余的天数是否为7的倍数!
如果为7的倍数,就看有几个7,把前面计算一周的时间往后推,类似这样,用Calender日历类进行day参数的set.
int m = instance.get(Calendar.MONTH);
int y = instance.get(Calendar.YEAR);
int d = instance.get(Calendar.DATE);
for (int i = 0; i < days / 7 ; i++) {
instance.set(y, m, d + 7 * i);
String day = sdf.format(instance.getTime());
}
##############################################
那如果不为7的倍数呢?剩余的天数我要怎么考虑?如果今天的日期到月底不足7天,我又要怎么校验不去计算后面的时间呢?
这个思路理论上可以实现,但是如果掺杂着业务的对象参数设置,考虑不同情况就会显得很乱,怎么样才能避免这种校验呢?
我突然想到我们一个月最少不过28天,最多不过31天。那我可以把剩余不足7天的天数日期当做一个7来处理,这样就可以 避免多余复杂的校验判断。
###################################
代码就修改成这样了,主要计算日期代码,业务代码自行添加。
int m = instance.get(Calendar.MONTH);
int y = instance.get(Calendar.YEAR);
int d = instance.get(Calendar.DATE);
for (int i = 0; i < days / 7 +1 ; i++) {
instance.set(y, m, d + 7 * i);
String day = sdf.format(instance.getTime());
}
每次往后多算一周的时间,不足一周的当一周来计算。
通过修改测试,行得通!!!
但是这样会导致数据里面会出现不属于本月的数据,虽然前端是按照月进行数据展示,不影响正常的展示使用,但是万一出了我没有考虑到的问题呢?
而且在处理数据的时候,最忌讳产出多余的数据,就像我们在写sql时,查询某个表中的某个字段,不会选择查全表去拿一样。
多余的字段,多余的月份数据给前端是无意义的,反而可能会出一下不必要的问题。
#######################################那么现在的问题是如何处理多余的数据???
其实处理起来也挺简单的。比如我们现在是2月分的数据,出现了多余属于3月份的数据,因为我们的逻辑是往后多算一周。
那么我们可以把当前数据遍历,拿出每条数据年月日对应的月份。在通过当前new Date()计算是几月份。
如果数据中的数据与当前月份+1相等,那么就把这个数据存到临时集合中。原集合removeAll临时集合剩下的就是当前月份数据。
代码贴出###################################
Calendar c = Calendar.getInstance();
c.setTime(DateUtils.parseDate(sdf.format(parse)));
int nowMonth = c.get(Calendar.MONTH); // new Date()拿出当前月份
ArrayList<XmWorkingScheduling> OList = new ArrayList();
for (XmWorkingScheduling xmWorkingScheduling : monthList) {
Date day = xmWorkingScheduling.getDay();
Calendar instance = Calendar.getInstance();
instance.setTime(DateUtils.parseDate(sdf.format(day)));
int m = instance.get(Calendar.MONTH);// 拿出数据中的月份
if (m == nowMonth + 1) {
OList.add(xmWorkingScheduling);
}
}
这里需要注意的是日历类拿月份,int m = instance.get(Calendar.MONTH);######0是1月,1是2月。
########################################################################
那么到现在,周班转换为对应的年月日,一个月的数据基本上已经处理完毕。
但是目前还有一个问题,需求后台需要根据月份查询对应月份一月数据?
##############################################################
首先看一下传入查询参数的格式,我这边项目的格式是“20222”代表2022年2月,就需要对应的fomat转换一下。
SimpleDateFormat sd = new SimpleDateFormat("yyyyM");
Integer month = scheduling.getMonth(); // 拿年月参数
Date parse = sd.parse(month.toString());
这里我们可以拿到date,可以把之前的工具类参数修改一下,直接把当前的月份计算转换为传入年月。
我这边因为其他业务需要用到new Date()计算的map。所以我选择复制一份,直接修改工具参数
#########################################################
/**
* 根据传入年月计算周几,进而计算一周的map,方便 业务使用。 第一个参数是周几,第二个是传入的年月“20222”格式
*/
public static String getDayByMonthFirst(Integer dayType,Integer month) throws ParseException {
SimpleDateFormat sdf = new SimpleDateFormat("yyyyM");
String s = month.toString();
Date parse = sdf.parse(s);
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
// 拿出本月第一天
Calendar c = Calendar.getInstance();
String f = format.format(parse);
c.setTime(DateUtils.parseDate(f));
int mm = c.get(Calendar.MONTH);
int yy = c.get(Calendar.YEAR);
c.set(yy,mm,1);
String dayO = format.format(c.getTime());
Date date = DateUtils.parseDate(dayO);
// key为星期,value为年月日字符串
HashMap<String, String> map = new HashMap<>();
String dateToWeek = dateToWeek(dayO); // 根据年月计算周几
map.put(dateToWeek, dayO);
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000))), format.format(new Date(date.getTime() + 86400000)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 2))), format.format(new Date(date.getTime() + 86400000 * 2)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 3))), format.format(new Date(date.getTime() + 86400000 * 3)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 4))), format.format(new Date(date.getTime() + 86400000 * 4)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 5))), format.format(new Date(date.getTime() + 86400000 * 5)));
map.put(dateToWeek(format.format(new Date(date.getTime() + 86400000 * 6))), format.format(new Date(date.getTime() + 86400000 * 6)));
return map.get(dayType.toString());
}
####################################################################
总结一下:
1.通过传入的年月日,进而通过年月日转换为周几的工具,将周几和年月日计算一周存入Map中
2.通过传入的周几拿出一周年月日,通过剩余天数取模+1,计算满周的后期年月日,有几周多+1,把不满7天的剩余天数当一周来计算。
3.因为是多计算了一周,其中可能有部分属于后面月份的数据。通过日历类拿月份进行判断,把不属于本月份的数据剔除。 完美完工!!!
PS:
只是记录工作中的思路逻辑及设计想法,方便自我复盘。如有更好的想法和思路,欢迎讨论。