实战:求年月日时间前后遇到的坑和解决方式
前言
这周接到一个时间转换任务需要处理,本来没什么问题,后来完成后发现时间有偏差,又重写了一遍代码,感觉很有记录必要性,希望看过的小伙伴可以避坑。照例,先说结论。
正确实例:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(CommonConstants.DATE_FORMAT); LocalDateTime now = LocalDateTime.now();
错误实例:
Calendar calendar = Calendar.getInstance();
结果:如果我们使用了错误的工具类Calendar,求出的时间在时分秒中会有偏差,打到几小时,小到十几秒。这个时间的偏差是我们无法忍受的。
需求
这个工作是要求一个接口传输给我们一部分参数,然后根据参数求出对应的数据,比如昨天今天,三小时、天、月、年后等等。下面是代码实例,照例先放正确的,错误的留给大家参考。
//求出年月日小时对应要求的时间 public Intent dateForParams2(Intent intent, String time) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(CommonConstants.DATE_FORMAT); LocalDateTime now = LocalDateTime.now(); String endTime = now.format(formatter); // 将时间向前推移1小时 if (CommonConstants.HeHaiTimeKey.HOUR_1.equals(time)) { now = now.minusHours(1); } if (CommonConstants.HeHaiTimeKey.HOUR_3.equals(time)) { now = now.minusHours(3); } if (CommonConstants.HeHaiTimeKey.HOUR_24.equals(time)) { now = now.minusDays(1); } if (CommonConstants.HeHaiTimeKey.HOUR_48.equals(time)) { now = now.minusDays(2); } if (CommonConstants.HeHaiTimeKey.HOUR_72.equals(time)) { now = now.minusDays(3); } // 将日期向前推移3天 if (CommonConstants.HeHaiTimeKey.DAY_3.equals(time)) { now = LocalDateTime.of( now.minusDays(3).toLocalDate(), LocalTime.of(8, 0, 0) // 设置为8点整 ); } if (CommonConstants.HeHaiTimeKey.DAY_7.equals(time)) { now = LocalDateTime.of( now.minusDays(7).toLocalDate(), LocalTime.of(8, 0, 0) ); } if (CommonConstants.HeHaiTimeKey.DAY_15.equals(time)) { now = LocalDateTime.of( now.minusDays(15).toLocalDate(), LocalTime.of(8, 0, 0) ); } if (CommonConstants.HeHaiTimeKey.DAY_30.equals(time)) { now = LocalDateTime.of( now.minusDays(30).toLocalDate(), LocalTime.of(8, 0, 0) ); } // 将月份向前推移3个月 if (CommonConstants.HeHaiTimeKey.THREE_MONTH.equals(time)) { now = LocalDateTime.of( now.minusMonths(3).toLocalDate(), LocalTime.of(8, 0, 0) ); } if (CommonConstants.HeHaiTimeKey.HALF_YEAR.equals(time)) { // 将月份向前推移6个月 now = LocalDateTime.of( now.minusMonths(6).toLocalDate(), LocalTime.of(8, 0, 0) ); } // 将年份向前推移1年 if (CommonConstants.HeHaiTimeKey.ONE_YEAR.equals(time)) { now = LocalDateTime.of( now.minusYears(1).toLocalDate(), LocalTime.of(8, 0, 0) ); } if (CommonConstants.HeHaiTimeKey.THREE_YEAR.equals(time)) { now = LocalDateTime.of( now.minusYears(3).toLocalDate(), LocalTime.of(8, 0, 0) ); } if (CommonConstants.HeHaiTimeKey.FIVE_YEAR.equals(time)) { now = LocalDateTime.of( now.minusYears(5).toLocalDate(), LocalTime.of(8, 0, 0) ); } if (CommonConstants.HeHaiTimeKey.TEN_YEAR.equals(time)) { now = LocalDateTime.of( now.minusYears(10).toLocalDate(), LocalTime.of(8, 0, 0) ); } //设置早上8点 if (CommonConstants.HeHaiTimeKey.TODAY.equals(time)) { now = LocalDateTime.of( now.toLocalDate(), // 使用当前日期 LocalTime.of(8, 0, 0) // 设置为8点整 ); } if (CommonConstants.HeHaiTimeKey.YESTERDAY.equals(time)) { //减去1天 now = LocalDateTime.of( now.minusDays(1).toLocalDate(), LocalTime.of(8, 0, 0) ); // 结束日期为今日8点整 endTime = eightForNow2(0); } if (CommonConstants.HeHaiTimeKey.LAST_DAY.equals(time)) { //减去2天 now = LocalDateTime.of( now.minusDays(2).toLocalDate(), LocalTime.of(8, 0, 0) ); // 结束日期为昨日8点整 endTime = eightForNow2(1); } String startTime = now.format(formatter); log.info("输出开始时间:{}", startTime); intent.setStartTime(startTime); intent.setEndTime(endTime); return intent; }
/** * 求出早8点 */ public String eightForNow2(Integer day) { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(CommonConstants.DATE_FORMAT); LocalDateTime now = LocalDateTime.now(); if (day != null) { if (day == 0) { now = LocalDateTime.of( now.toLocalDate(), // 使用当前日期 LocalTime.of(8, 0, 0) // 设置为8点整 ); } else { now = LocalDateTime.of( now.minusDays(day).toLocalDate(), LocalTime.of(8, 0, 0) ); } } return now.format(formatter); }
这个没有集成一个工具类是因为需求开发时间小,而且要求时间短,再加上是使用频率低。有常用的可以集成到你们的时间工具类中。
-------------------------------错误-------------------------------
/** * 根据Params求出不同的时间 */ public Intent dateForParams(Intent intent, String time) { SimpleDateFormat format = new SimpleDateFormat(CommonConstants.DATE_FORMAT); Calendar calendar = Calendar.getInstance(); //获取日历实例 String endTime = format.format(calendar.getTime());//后去结束时间 calendar.setTime(date); //将当前时间设置给日历实例 int hour = calendar.get(Calendar.HOUR_OF_DAY); // 获取当前的小时数 // 将时间向前推移1小时 if (CommonConstants.HeHaiTimeKey.HOUR_1.equals(time)) { if (hour < 1) { calendar.add(Calendar.DAY_OF_MONTH, -1); // 将日期向前推移1天 hour += 24; // 计算出对应的小时数 calendar.add(Calendar.HOUR_OF_DAY, hour - 1); } else { calendar.add(Calendar.HOUR_OF_DAY, -1); } } if (CommonConstants.HeHaiTimeKey.HOUR_3.equals(time)) { if (hour < 1) { calendar.add(Calendar.DAY_OF_MONTH, -1); // 将日期向前推移1天 hour += 24; // 计算出对应的小时数 calendar.add(Calendar.HOUR_OF_DAY, hour - 3); } else { calendar.add(Calendar.HOUR_OF_DAY, -3); } } if (CommonConstants.HeHaiTimeKey.HOUR_24.equals(time)) { calendar.add(Calendar.DAY_OF_MONTH, -1); } if (CommonConstants.HeHaiTimeKey.HOUR_48.equals(time)) { calendar.add(Calendar.DAY_OF_MONTH, -2); } if (CommonConstants.HeHaiTimeKey.HOUR_72.equals(time)) { calendar.add(Calendar.DAY_OF_MONTH, -3); } // 将日期向前推移3天 if (CommonConstants.HeHaiTimeKey.DAY_3.equals(time)) { calendar.add(Calendar.DAY_OF_MONTH, -3); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); } if (CommonConstants.HeHaiTimeKey.DAY_7.equals(time)) { calendar.add(Calendar.DAY_OF_MONTH, -7); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); } if (CommonConstants.HeHaiTimeKey.DAY_15.equals(time)) { calendar.add(Calendar.DAY_OF_MONTH, -15); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); } if (CommonConstants.HeHaiTimeKey.DAY_30.equals(time)) { calendar.add(Calendar.DAY_OF_MONTH, -30); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); } // 将月份向前推移3个月 if (CommonConstants.HeHaiTimeKey.THREE_MONTH.equals(time)) { calendar.add(Calendar.MONTH, -3); } if (CommonConstants.HeHaiTimeKey.HALF_YEAR.equals(time)) { // 将月份向前推移6个月 calendar.add(Calendar.MONTH, -6); } // 将年份向前推移1年 if (CommonConstants.HeHaiTimeKey.ONE_YEAR.equals(time)) { calendar.add(Calendar.YEAR, -1); } if (CommonConstants.HeHaiTimeKey.THREE_YEAR.equals(time)) { calendar.add(Calendar.YEAR, -3); } if (CommonConstants.HeHaiTimeKey.FIVE_YEAR.equals(time)) { calendar.add(Calendar.YEAR, -5); } if (CommonConstants.HeHaiTimeKey.TEN_YEAR.equals(time)) { calendar.add(Calendar.YEAR, -10); } //设置早上8点 if (CommonConstants.HeHaiTimeKey.TODAY.equals(time)) { calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); } if (CommonConstants.HeHaiTimeKey.YESTERDAY.equals(time)) { //减去1天 calendar.add(Calendar.DAY_OF_MONTH, -1); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); // 结束日期为今日8点整 endTime = eightForNow(null); intent.setEndTime(endTime); } if (CommonConstants.HeHaiTimeKey.LAST_DAY.equals(time)) { //减去2天 calendar.add(Calendar.DAY_OF_MONTH, -2); calendar.set(Calendar.HOUR_OF_DAY, 8); calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); // 结束日期为昨日8点整 endTime = eightForNow(1); intent.setEndTime(endTime); } String startTime; Date dayTime = calendar.getTime(); if (CommonConstants.HeHaiTimeKey.REAL_TIME.equals(time)) { startTime = endTime; } else { startTime = format.format(dayTime); //将时间格式化为字符串 } log.info("输出开始时间:{}", startTime); intent.setStartTime(startTime); intent.setEndTime(endTime); return intent; } /** * 求出早8点 */ public String eightForNow(Integer day) { Calendar calendar = Calendar.getInstance(); //获取日历实例 calendar.setTime(date); //将当前时间设置给日历实例 if (day != null) { calendar.add(Calendar.DAY_OF_MONTH, -day); //减去对应天数 } calendar.set(Calendar.HOUR_OF_DAY, 8); //设置早上8点 calendar.set(Calendar.MINUTE, 0); calendar.set(Calendar.SECOND, 0); Date yesterday8am = calendar.getTime(); //获取昨天早上8点的时间 SimpleDateFormat format = new SimpleDateFormat(CommonConstants.DATE_FORMAT); String formattedDateTime = format.format(yesterday8am); log.info("输出开始时间:{}", formattedDateTime); return formattedDateTime; }
Calendar是Java中处理日期和时间的类,它提供了各种实用方法来操作日历、时区和时间等信息。以前,Java的日期时间类主要是使用Date和SimpleDateFormat,但是这两个类存在一些问题,如线程不安全,可变性等,因此Java 1.1中引入了Calendar类来替代它们。
Calendar类是一个抽象类,不能直接创建对象,可以通过getInstance()方法获取它的实例。通过set()方法设置日期和时间信息,getTime()方法获取Date类型的时间,get()方法获取年月日等信息。
Calendar类提供了对时间进行加减的方法,add()方法用于加减某个时间单位,例如,可以使用add(Calendar.DATE, 1)增加一天,也可以使用add(Calendar.MONTH, -1)减少一个月。roll()方法则是这样做的一种变体,它只对指定的字段进行修改,而不会对较高的字段进行更改。
Calendar类也提供了很多有用的方法来操纵和显示日期和时间,如getFirstDayOfWeek()获取当前的星期起始日,getMinimum()获取给定日历字段的最小值等等。
尽管Calendar类有很多优点,它仍然没有解决Date类的基本问题。在Java 8中,LocalDateTime类被引入作为替代Calendar和Date的更简单、更灵活的实现。本地日期时间的类提供了Java程序员可以更自然地处理日期和时间的方法,避免了时间区的混淆和线程安全问题。
LocalDateTime是Java 8新增加的一个日期时间类,代表的是一个不带时区的日期和时间,具有不可变性,用于处理本地日期和时间。它的可以存储到精确到纳秒的时间。
LocalDateTime的初始化可以通过now()调用获取当前的日期和时间,也可以通过of()方法创建指定的日期和时间。其中,now()方法的具体实现是通过系统时钟获取当前的时间,of()方法则接受七个参数,分别是年、月、日、时、分、秒、纳秒顺序。
LocalDateTime还提供了很多方法来操纵日期和时间,比如加减日期时间、计算日期之间的间隔、格式化日期时间等。这样可以很方便地进行日常的开发工作。对于需要考虑时区的应用来说,Java 8还提供了ZonedDateTime类。
LocalDateTime是一种非常实用的日期和时间处理类,它可以满足大多数应用对日期和时间的需求。
上面都是一些官网给出的答案,由此我们也可以看出,使用LocalDateTime是更好的一种选择,还在用calender的可以尝试替换了,不要停留在旧时代里。
代码就不具体讲解了也不是很难,注释也挺多,有什么不懂得可以评论下方提出,看到后会抓紧回复的。
ps:有的小伙伴可能的确是刚接触,这里提供一个calender的示例,自己试着修改成LocalDateTime,前者你可以不会,后者不行哦。
public static void main(String[] args) throws ParseException { String dateTimeString = "2023-06-13 02:00:00"; SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date1 = format.parse(dateTimeString); // 解析为 Date 对象 Calendar calendar = Calendar.getInstance(); //获取日历实例 calendar.setTime(date1); //将当前时间设置给日历实例 //这里零时转换可以忽略,LocalDateTime没有这方面的烦恼 int hour = calendar.get(Calendar.HOUR_OF_DAY); // 获取当前的小时数 if (hour < 1) { // 如果小时数小于1,则需要特殊处理 calendar.add(Calendar.DAY_OF_MONTH, -1); // 将日期向前推移1天 hour += 24; // 计算出对应的小时数 } //calendar.set(Calendar.HOUR_OF_DAY, hour - 72); // 将时间向前推移1小时 calendar.add(Calendar.YEAR, -10); // 将年份向前推移10年 Date yesterday8am = calendar.getTime(); String formattedDateTime = format.format(yesterday8am); //将时间格式化为字符串 System.out.println("输出结果:"+formattedDateTime); //输出结果 }
今天就到这里吧,感觉有用的小伙伴可以点个赞,你的支持就是我更新的最大动力!
#java##实战#不秃头