需求
做报表统计时需要按年、月、日三个范围进行统计,后端从前端获取一个时间戳,然后根据范围得到两个时间戳(日的话就是当日的00:00到第二天的00:00, 月的话就是当月一号的00:00到下个月一号的00:00, 年的话...)
问题关键
在处理过程中,我们发现其实并不难解决,主要是代码要优雅,在处理以下部分时代码不好组织。
- 时分秒的清零
一开始使用SimpleDateFormat将日期转换字符串,然后将字符串转换回来,这里会引入parse的异常(字符串转换成日期)使得后期调用需要处理不存在的异常(这里字符串是日期转换过来的,再转成日期肯定不会出错,但是程序不知道)。而用Date的setHour方法有点不好的就是这个方法已经被弃用了。 - 日期往后加(年,月,日)
Date是没有年月日的增加的。
解决
- 方法一(推荐)
使用LocalDate类(java8开始支持),简单,安全
public static TimeFrame day(Long timestamp){
LocalDate localDate = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDate();
Long start = localDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
localDate = localDate.plusDays(1);
Long end = localDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
return new TimeFrame(start, end);
}
public static TimeFrame month(Long timestamp) {
LocalDate localDate = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDate();
localDate = localDate.withDayOfMonth(1);
Long start = localDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
localDate = localDate.plusMonths(1);
Long end = localDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
return new TimeFrame(start, end);
}
public static TimeFrame year(Long timestamp) {
LocalDate localDate = Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDate();
//将日期置为1月1日
localDate = localDate.withDayOfYear(1);
Long start = localDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
//将年份加1
localDate = localDate.plusYears(1);
Long end = localDate.atStartOfDay(ZoneId.systemDefault()).toEpochSecond();
return new TimeFrame(start, end);
}
这里TimeFrame是我自定义的一个类,有两个属性start和end,分别表示时间范围的起始和结束(按秒的时间戳)
- 方法二
如果项目java版本过低(小于8),那就不能用LocalDate了。
public static TimeFrame year(Long timestamp) {
Calendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(timestamp);
//时分秒清零
clear(calendar);
calendar.set(Calendar.DAY_OF_YEAR, 1);
Long start = calendar.getTimeInMillis() / 1000;
calendar.add(Calendar.YEAR, 1);
Long end = calendar.getTimeInMillis() / 1000;
return new TimeFrame(start, end);
}
public static void clear(Calendar calendar) {
calendar.set(Calendar.HOUR_OF_DAY, 0);
calendar.set(Calendar.MINUTE, 0);
calendar.set(Calendar.SECOND, 0);
calendar.set(Calendar.MILLISECOND, 0);
}
LocalDate的接口
getYear() int 获取当前日期的年份
getMonth() Month 获取当前日期的月份对象
getMonthValue() int 获取当前日期是第几月
getDayOfWeek() DayOfWeek 表示该对象表示的日期是星期几
getDayOfMonth() int 表示该对象表示的日期是这个月第几天
getDayOfYear() int 表示该对象表示的日期是今年第几天
withYear(int year) LocalDate 修改当前对象的年份
withMonth(int month) LocalDate 修改当前对象的月份
withDayOfMonth(int dayOfMonth) LocalDate 修改当前对象在当月的日期isLeapYear() boolean 是否是闰年
lengthOfMonth() int 这个月有多少天
lengthOfYear() int 该对象表示的年份有多少天(365或者366)
plusYears(long yearsToAdd) LocalDate 当前对象增加指定的年份数
plusMonths(long monthsToAdd) LocalDate 当前对象增加指定的月份数plusWeeks(long weeksToAdd) LocalDate 当前对象增加指定的周数
plusDays(long daysToAdd) LocalDate 当前对象增加指定的天数
minusYears(long yearsToSubtract) LocalDate 当前对象减去指定的年数minusMonths(long monthsToSubtract) LocalDate 当前对象减去注定的月数minusWeeks(long weeksToSubtract) LocalDate 当前对象减去指定的周数minusDays(long daysToSubtract) LocalDate 当前对象减去指定的天数compareTo(ChronoLocalDate other) int 比较当前对象和other对象在时间上的大小,返回值如果为正,则当前对象时间较晚,
isBefore(ChronoLocalDate other) boolean 比较当前对象日期是否在other对象日期之前
isAfter(ChronoLocalDate other) boolean 比较当前对象日期是否在other对象日期之后
isEqual(ChronoLocalDate other) boolean 比较两个日期对象是否相等
网友评论