由于部门业务主要聚焦于工业4.0的领域,最近涉及到了比较多的双碳(碳中和,碳排放)的数据统计和分析。凡是涉及到数据,则肯定会连带出各种图标数据,也就离不开时间和数据的关系。
因此为了方便,自己抽出了一份平时我写给自己用的日期图表工具类(折线图,柱状图)
首先是要有一个对应的x轴y轴返回类啦,可以根据传入的T来给到具体的y轴类型
/**
* x轴y轴类,y轴可以传入具体的类型
* @param
*/
class TimeValChartVO<T> {
List<String> xAxis;
List<T> yAxis;
public List<String> getxAxis() {
return xAxis;
}
.......
//省略Getter和Setter,toString,hashcode,equals
接着就是获得各种类型的x轴,(当天的时间点,当周的星期,当月的天,当年的月份)
/**
* 获取当天任意某个时间段里的每个时间点 ---(传入开始的时间点和结束的时间点)
* @param startTime 开始时间点
* @param endTime 结束时间点
* @return
*/
public static List<String> getDayXAxis(int startTime, int endTime) {
//一个小时一次的查询
ArrayList<String> x = new ArrayList<>();
for (int i = startTime; i <= endTime; i++) {
x.add(i + "点");
}
return x;
}
/**
* 取本周任意某个时间段(几天内)里的星期 ---(传入开始的星期和结束的星期)
* @param startTime 开始周几
* @param endTime 结束周几
* @return
*/
public static List<String> getWeekDayXAxis(Date startTime, Date endTime) {
List<String> x = new ArrayList<>();
String[] weekDays = {"星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六"};
Calendar c = Calendar.getInstance();
c.setTime(startTime);
//计算开始时间是周几
int w = c.get(Calendar.DAY_OF_WEEK) - 1;
if (w < 0) {
w = 0;
}
c.setTime(endTime);
int e = c.get(Calendar.DAY_OF_WEEK) - 1;
//判断总长度,比他小,就是在前面,比他大则
int len = e > w ? Math.abs(e - w) + 1 : weekDays.length - w + e + 1;
while (len > 0) {
x.add(weekDays[w]);
w = (w + 1) % weekDays.length;
len--;
}
return x;
}
/**
* 获取每个时间
* @param formatStr 日期展示格式
* @param startDate 开始时间
* @param endDate 结束时间
* @return
*/
public static List<String> getDateXAxisData(String formatStr, LocalDateTime startDate, LocalDateTime endDate){
//日期格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatStr);
ArrayList<String> x = new ArrayList<>();
//遍历给定的日期期间的每一天
for (int i = 0; !Duration.between(startDate.plusDays(i), endDate).isNegative(); i++) {
//添加日期
x.add(startDate.plusDays(i).format(formatter));
}
return x;
}
/**
* 获取每个月份
* @param formatStr 月份展示格式
* @param startDate 开始月份
* @param endDate 结束月份
* @return
*/
public static List<String> getMonthXAxisData(String formatStr, LocalDateTime startDate, LocalDateTime endDate){
//日期格式化
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(formatStr);
List<String> xAxis = new ArrayList<>();
//遍历给定的日期期间的每一天
for (int i = 0; !Duration.between(startDate.plusMonths(i), endDate).isNegative(); i++) {
//添加日期
xAxis.add(startDate.plusMonths(i).format(formatter));
}
return xAxis;
}
对应的参考SQL示例(具体的示例可以按需搜索):
SELECT DATE(分组时间字段) AS 对象时间字段,SUM(统计的数值字段) AS 对象的数值字段 FROM 表名
WHERE 分组时间字段 BETWEEN 开始时间 AND 结束时间
GROUP BY 对象的数值字段
ORDER BY 对象的数值字段 DESC
最后可以根据个人需要把返回的对象转成map,方便遍历处理,附上自己的转map方法(其中,keyFieldName对应map的key,valueFieldName对应map的key,T代表map的value具体类型):
/**
* 把key-value对象转map
* @param list
* @param t
* @param keyFieldName
* @param valueFieldName
* @return
* @param
*/
private <T> Map<String, T> getDateNumsMap(List<?> list, Class<T> t,String keyFieldName,String valueFieldName) {
Map<String, T> map = new HashMap<>(16);
list.forEach(f ->{
try {
Field at = f.getClass().getDeclaredField("at");
Field val = f.getClass().getDeclaredField("val");
at.setAccessible(true);
val.setAccessible(true);
map.put((String) at.get(f), (T)val.get(f));
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
});
return map;
}
然后还有我自己的一个遍历时间x轴,给sql缺少统计数据的value填上默认值(比如0,1,null那种)
/**
* 通过传入的时间列表和数据流,填充到对应的xy点位上
* @param dateTimeList 完整的时间列
* @param data 统计出来的数据集合
* @param initVal 当map为空需要的默认值(0,null...)
* @return
* @param
*/
public <T> List<T> completionYAxisData(List<String> dateTimeList, Map<String,?> data, T initVal){
ArrayList<T> dateList = new ArrayList<>(16);
for(int i=0;i<xAxisData.size();i++){
if(data == null ||data.get(xAxisData.get(i))==null){
dateList.add(i,initVal);
}else{
dateList.add(i,(T)data.get(xAxisData.get(i)));
}
}
return dateList;
}