【Hutool】DateUtil.endOfHour、DateUtil.endOfDay得到的时间保存到MySQL时会增加一秒

【Hutool】DateUtil.endOfHour、DateUtil.endOfDay得到的时间保存到MySQL时会增加一秒

一、问题分析

冷知识:MySQL数据库对于毫秒大于 500的数据进行进位,所以就造成了 MySQL中的时间多一秒。

image-20250408145106417.

一般数据库表的字段类型 datetime/timestamp长度都是设置为 0



二、测试代码

  1. 获取某小时的结束时间 CalendarUtil.ceiling(date.toCalendar(), DateField.HOUR_OF_DAY, true)
public static void main(String[] args) {
    DateTime date = DateUtil.parse("2025-04-08 14:00:00.499");
    // date = 2025-04-08 14:00:00
    System.out.println("date = " + date);

    // date.millisecond() = 499
    System.out.println("date.millisecond() = " + date.millisecond());

    // endOfHour.millisecond() = 999
    DateTime endOfHour = DateUtil.endOfHour(date);
    System.out.println("endOfHour.millisecond() = " + endOfHour.millisecond());

    // 核心代码:
    Calendar calendar = CalendarUtil.ceiling(date.toCalendar(), DateField.HOUR_OF_DAY, true);
    DateTime dateTime = new DateTime(calendar);
    // dateTime = 2025-04-08 14:59:59
    System.out.println("dateTime = " + dateTime);
    // dateTime.millisecond() = 0
    System.out.println("dateTime.millisecond() = " + dateTime.millisecond());
}

  1. 获取某天的结束时间 CalendarUtil.ceiling(date.toCalendar(), DateField.DAY_OF_MONTH, true)
public static void main(String[] args) {
    DateTime date = DateUtil.parse("2025-04-08 14:00:00.499");
    // date = 2025-04-08 14:00:00
    System.out.println("date = " + date);

    // date.millisecond() = 499
    System.out.println("date.millisecond() = " + date.millisecond());

    // endOfDay.millisecond() = 999
    DateTime endOfDay = DateUtil.endOfDay(date);
    System.out.println("endOfDay.millisecond() = " + endOfDay.millisecond());

    // 核心代码:
    Calendar calendar = CalendarUtil.ceiling(date.toCalendar(), DateField.DAY_OF_MONTH, true);
    // System.out.println("calendar.getTime() = " + calendar.getTime());
    DateTime dateTime = new DateTime(calendar);
    // dateTime = 2025-04-08 23:59:59
    System.out.println("dateTime = " + dateTime);
    // dateTime.millisecond() = 0
    System.out.println("dateTime.millisecond() = " + dateTime.millisecond());
}


⭐三、解决方案⭐

truncateMillisecond设置成 true即可截断毫秒值(将毫秒数设为0),避免 MySQL的进位问题。

🔨 获取某小时的结束时间 DateUtil.endOfHour(date)替换代码:

Calendar calendar = CalendarUtil.ceiling(date.toCalendar(), DateField.HOUR_OF_DAY, true);
DateTime dateTime = new DateTime(calendar);

🔧 获取某天的结束时间 DateUtil.endOfDay(date)替换代码:

Calendar calendar = CalendarUtil.ceiling(date.toCalendar(), DateField.DAY_OF_MONTH, true);
DateTime dateTime = new DateTime(calendar);


四、追根溯源

🔎 cn.hutool.core.date.DateModifier类下,将 truncateMillisecond设置成 true即可截断毫秒值(将毫秒数设为0),避免 MySQL的进位问题。

/**
 * ......
 * @param truncateMillisecond 是否归零毫秒
 * @return 修改后的{@link Calendar}
 * @since 5.7.5
 */
public static Calendar modify(Calendar calendar, int dateField, ModifyType modifyType, boolean truncateMillisecond) {
    // ......

    final int endField = truncateMillisecond ? Calendar.SECOND : Calendar.MILLISECOND;
    // ......

    if (truncateMillisecond) {
        // 将毫秒数设为0(将时间中的毫秒数去除,只保留到秒)
        calendar.set(Calendar.MILLISECOND, 0);
    }

    return calendar;
}

DateUtil.endOfHour(date)DateUtil.endOfDay(date)默认 truncateMillisecond都为 false

以下只举例 DateUtil.endOfDay(date)源码,其它 DateUtil.endOfXxx类似:

image-20250408155158680.



五、参考文章

  1. 【CSDN】Java--new Date插入mysql数据库,数据库时间多一秒问题.
  2. 【CSDN】MySQL数据库对于毫秒大于500的数据会进位.
  3. 【CSDN】JDBC - new Date插入mysql数据库,数据库时间多一秒问题.
  4. 【CSDN】hutool的bug之 DateUtil.endOfDay(DateUtil.date()).

六、彩蛋

🔨 :hammer:

:hammer:

🔧 :wrench:

:wrench:
posted @ 2025-04-08 16:18  软柠柠吖  阅读(185)  评论(0)    收藏  举报