使用Calendar生成指定格式日期遇异常:时分错误、日期不符求助
问题排查与修复方案
一、去年同月1日00:00:00.000生成错误
问题原因
代码里用了Calendar.HOUR,这是12小时制字段,取值范围0-11(对应12AM到11AM、12PM到11PM)。设置c.set(Calendar.HOUR, 0)时,实际是把时间设为当天的12点(上午/下午取决于原时间时段),所以才会出现12:00:00.000的错误结果。
修复代码
把Calendar.HOUR替换为Calendar.HOUR_OF_DAY(24小时制字段,取值0-23):
private String getLastYear() { DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); Calendar c = Calendar.getInstance(); c.add(Calendar.YEAR, -1); c.set(Calendar.DAY_OF_MONTH, 1); c.set(Calendar.HOUR_OF_DAY, 0); // 替换为24小时制字段 c.set(Calendar.MINUTE, 0); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); return format.format(c.getTime()); }
二、上月最后一天23:59:59.999生成错误
问题原因
直接对当前日期执行c.add(Calendar.MONTH, -1)会触发Calendar的自动调整机制:比如当前是3月31日,减一个月后会变成2月31日,但2月没有31天,Calendar会自动把日期调整为3月3日(平年)或3月2日(闰年)。此时再设置DAY_OF_MONTH为当月最大天数,实际取的是调整后月份的最大天数,最终得到的不是上月最后一天。
修复代码
先把日期调整到当月第一天,再减一个月定位到上月第一天,最后设置为上月最大天数:
private String getPreviousMonth() { DateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); // 匹配目标格式 Calendar c = Calendar.getInstance(); c.set(Calendar.DAY_OF_MONTH, 1); // 先切换到当月第一天 c.add(Calendar.MONTH, -1); // 减一个月,得到上月第一天 c.set(Calendar.DAY_OF_MONTH, c.getActualMaximum(Calendar.DAY_OF_MONTH)); // 设置为上月最后一天 c.set(Calendar.HOUR_OF_DAY, 23); // 统一用24小时制字段 c.set(Calendar.MINUTE, 59); c.set(Calendar.SECOND, 59); c.set(Calendar.MILLISECOND, 999); return format.format(c.getTime()); }
额外优化建议
如果是Java 8及以上版本,建议使用java.time新日期API,比Calendar更简洁不易出错:
// 生成去年同月1日00:00:00.000 private String getLastYear() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); LocalDateTime lastYearFirstDay = LocalDateTime.now() .minusYears(1) .withDayOfMonth(1) .withHour(0) .withMinute(0) .withSecond(0) .withNano(0); return lastYearFirstDay.format(formatter); } // 生成上月最后一天23:59:59.999 private String getPreviousMonth() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS"); YearMonth lastMonth = YearMonth.now().minusMonths(1); LocalDateTime lastDayOfLastMonth = lastMonth.atEndOfMonth() .atTime(23, 59, 59, 999_000_000); return lastDayOfLastMonth.format(formatter); }
内容的提问来源于stack exchange,提问作者Marco Frag Delle Monache
相关产品推荐
相关产品推荐

