前言
在Java开发中,日期和时间的处理是一个常见问题。为了简化这个过程,许多开发者会使用第三方工具包,如Hutool。Hutool是一个Java工具包,提供了许多实用的功能,其中之一就是日期处理。日期时间工具类是Hutool的核心包之一,提供针对JDK中Date和Calendar对象的封装,封装对象如下:
封装对象 | 说明 |
---|---|
DateUtil | 针对日期时间操作提供一系列静态方法 |
DateTime | 提供类似于Joda-Time中日期时间对象的封装,继承自Date类,并提供更加丰富的对象方法。 |
FastDateFormat | 提供线程安全的针对Date对象的格式化和日期字符串解析支持。 |
DateBetween | 计算两个时间间隔的类,除了通过构造新对象使用外,相关操作也已封装在DateUtil和DateTime的相关方法中。 |
TimeInterval | 一个简单的计时器类,常用于计算某段代码的执行时间,提供包括毫秒、秒、分、时、天、周等各种单位的花费时长计算。 |
DatePattern | 提供常用的日期格式化模式,包括String类型和FastDateFormat两种类型。 |
Quarter | 季度枚举 |
Month | 月份枚举 |
Week | 周枚举 |
DateUnit | 日期时间单位,表示某个时间单位对应的毫秒数,常用于计算时间差。 |
一、概述
1.1 工具简介
Hutool 的 DateUtil 工具类是 Hutool 工具库中用于日期和时间处理的核心类之一,提供了许多静态方法,用于方便地处理常见的日期和时间操作。考虑到 Java 本身对日期时间的支持有限,并且 Date 和 Calendar 对象的并存导致各种方法使用混乱和复杂,故使用此工具类做了封装。这其中的封装主要是日期和字符串之间的转换,以及提供对日期的定位。
1.2 引入依赖
在使用Hutool工具之前,我们需要将Hutool添加到项目的依赖中。如果使用Maven构建项目,可以在 pom.xml 文件中添加以下依赖:
<!-- https://mvnrepository.com/artifact/cn.hutool/hutool-all -->
<dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>${hutool.version}</version>
</dependency>
Hutool-all 是一个 Hutool 的集成打包产品,由于考虑到“懒人”用户及分不清各个模块作用的用户,“无脑”引入 hutool-all 模块是快速开始和深入应用的最佳方式。如果你想像 SpringBoot 一样引入 Hutool,再由子模块决定用到哪些模块,你可以在父模块中加入:
<dependencyManagement><dependencies><dependency><groupId>cn.hutool</groupId><artifactId>hutool-bom</artifactId><version>${hutool.version}</version><type>pom</type><!-- 注意这里是import --><scope>import</scope></dependency></dependencies>
</dependencyManagement>
然后再在子模块中就可以引入自己需要的模块了:
<dependencies><dependency><groupId>cn.hutool</groupId><artifactId>hutool-core</artifactId></dependency>
</dependencies>
二、基本使用示例
2.1 计算生日
方法 | 部分参数 | 作用 |
---|---|---|
age(Date birthday, Date dateToCompare) | birthday:生日 dateToCompare:需要对比的日期 | 计算相对于dateToCompare的年龄,常用于计算指定生日在某年的年龄 |
ageOfNow(String birthDay) | birthDay:生日,标准日期字符串 | 生日转为年龄,计算法定年龄 |
ageOfNow(Date birthDay) | birthDay:生日 | 生日转为年龄,计算法定年龄 |
getChineseZodiac(int year) | 计算生肖,只计算1900年后出生的人 | |
getZodiac(int month, int day) | 通过生日计算星座 |
2.2 获取时间属性
2.2.1 获取当前时间
Hutool 提供了多种方式获取当前时间,例如当前时间戳、当前日期字符串等等。
方法 | 部分参数 | 作用 |
---|---|---|
DateTime date() | 将当前时间转换为DateTime对象 | |
DateTime date(Calendar calendar) | 根据已有 Calendar 转换为 DateTime对象 | |
DateTime dateSecond() | 当前时间,转换 DateTime 对象,忽略毫秒部分 | |
String now() | 当前时间,格式 yyyy-MM-dd HH:mm:ss | |
String today() | 当前日期,格式 yyyy-MM-dd | |
long current() | 当前时间的时间戳 | |
long currentSeconds() | 当前时间的时间戳(秒) |
2.2.2 获取当前时间属性
方法 | 部分参数 | 作用 |
---|---|---|
int getLastDayOfMonth(Date date) | 获得本月的最后一天 | |
int thisDayOfMonth() | 当前日期所在月份的第几周 | |
int thisDayOfWeek() | 当前日期是星期几 | |
int thisHour(boolean is24HourClock) | is24HourClock - 是否24小时制 | 当前日期的小时数部分 |
int thisMinute() | 当前日期的分钟数部分 | |
int thisMillisecond() | 当前日期的毫秒数部分 | |
int thisMonth() | 当前月份,从0开始计数 | |
int thisSecond() | 当前日期的秒数部分 | |
int thisWeekOfMonth() | 当前日期所在月份的第几周 | |
int thisWeekOfYear() | 当前日期所在年份的第几周 | |
thisYear | 今年 |
// 当前时间
Date date = DateUtil.date();
System.out.println(date);// Calendar转Date
System.out.println(DateUtil.date(Calendar.getInstance()));// 时间戳转Date
System.out.println(DateUtil.date(System.currentTimeMillis()));// 当前时间字符串,格式:yyyy-MM-dd HH:mm:ss
System.out.println(DateUtil.now());// 当前日期字符串,格式:yyyy-MM-dd
System.out.println(DateUtil.today());
2.2.3 获取时间部分属性
方法 | 部分参数 | 作用 |
---|---|---|
DateTime date() | 将当前时间转换为DateTime对象 | |
int year(Date date) | 获得年的部分 | |
int month(Date date) | 获得月份,从0开始计数 | |
int hour(Date date, boolean is24HourClock) | is24HourClock - 是否24小时制 | 获得指定日期的小时数部分 |
int minute(Date date) | 获得指定日期的分钟数部分 | |
int second(Date date) | 获得指定日期的秒数部分 | |
int millisecond(Date date) | 获得指定日期的毫秒数部分 |
Date date = DateUtil.date();// 获得年的部分
int year = DateUtil.year(date);// 获得月份,从0开始计数
int month = DateUtil.month(date);// 获得月份枚举
DateUtil.monthEnum(date).getValue();
2.2.4 获取指定时间属性
方法 | 部分参数 | 作用 |
---|---|---|
int dayOfMonth(Date date) | 获得指定日期是这个日期所在月份的第几天 | |
int dayOfWeek(Date date) | 获得指定日期是星期几,1表示周日,2表示周一 | |
dayOfWeekEnum | 获得指定日期是星期几 | |
int dayOfYear(Date date) | 获得指定日期是这个日期所在年的第几天 | |
int quarter(Date date) | 获得指定日期所属季度,从1开始计数 | |
String yearAndQuarter(Date date) | 获得指定日期年份和季节。例如[20131]表示2013年第一季度 | |
int lengthOfMonth(int month,boolean isLeapYear) | isLeapYear - 是否闰年 | 获得指定月份的总天数 |
int lengthOfYear(int year) | 获得指定年份的总天数 | |
int millisecond(Date date) | 获得指定日期的毫秒数部分 | |
int minute(Date date) | 获得指定日期的分钟数部分 |
2.3 获取某时间的开始、结束日期
有的时候我们需要获得每天的开始时间、结束时间,每月的开始和结束时间等等,DateUtil也提供了相关方法:
方法 | 部分参数 | 作用 |
---|---|---|
DateTime beginOfYear(Date date) | 获取某年的开始时间 | |
DateTime endOfYear(Date date) | 获取某年的结束时间 | |
DateTime beginOfQuarter(Date date) | 获取某季度的开始时间 | |
DateTime endOfQuarter(Date date) | 获取某季度的结束时间 | |
DateTime beginOfMonth(Date date) | 获取某月的开始时间 | |
DateTime endOfMonth(Date date) | 获取某月的结束时间 | |
DateTime beginOfWeek(Date date) | 获取某周的开始时间,周一为一周的开始 | |
beginOfWeek(Date date,boolean isMondayAsFirstDay) | isMondayAsFirstDay:是否周一做为一周的第一天 | 获取某周的开始时间 |
DateTime endOfWeek(Date date) | 获取某周的结束时间,周日为一周的结束 | |
endOfWeek(Date date,boolean isSundayAsLastDay) | isSundayAsLastDay:是否周日做为一周的最后一天 | 获取某周的结束时间 |
DateTime beginOfDay(Date date) | 获取某天的开始时间 | |
DateTime endOfDay(Date date) | 获取某天的结束时间 | |
beginOfHour(Date date) | 获取某小时的开始时间 | |
endOfHour(Date date) | 获取某小时的结束时间 | |
beginOfMinute(Date date) | 获取某分钟的开始时间 | |
endOfMinute(Date date) | 获取某分钟的结束时间 | |
beginOfSecond(Date date) | ||
DateTime beginOfSecond(Date date) | 获取秒级别的开始时间,即毫秒部分设置为0 |
String dateStr = "2022-11-09 22:33:23";
Date date = DateUtil.parse(dateStr);// 一天的开始,结果:2022-11-09 00:00:00
Date beginOfDay = DateUtil.beginOfDay(date);// 一天的结束,结果:2022-11-09 23:59:59
Date endOfDay = DateUtil.endOfDay(date);// 获取秒级别的开始时间,即毫秒部分设置为0
System.out.println(DateUtil.beginOfSecond(date));// 获取某周的开始时间
System.out.println(DateUtil.beginOfWeek(date));
2.4 日期时间计算
Hutool 提供了丰富的日期计算方法,例如获取某天的开始时间、结束时间,计算两个日期之间的天数、小时等等。
2.4.1 日期时间比较
方法 | 部分参数 | 作用 |
---|---|---|
int compare(Date date1,Date date2) | 日期比较。 如果date1 < date2,小于0,date1==date2返回0,date1 > date2 大于0 | |
boolean isIn(Date date,Date beginDate, Date endDate) | 当前日期是否在日期指定范围内 | |
boolean isSameDay(Date date1,Date date2) | 比较两个日期是否为同一天 | |
boolean isSameMonth(Date date1,Date date2) | 比较两个日期是否为同一月 | |
boolean isSameTime(Date date1,Date date2) | 比较两个日期的时间戳是否相同 | |
boolean isSameWeek(Date date1,Date date2) | 比较两个日期是否为同一周 |
2.4.2 日期时间偏移计算
日期或时间的偏移指针对某个日期增加或减少分、小时、天等等,达到日期变更的目的。Hutool也针对其做了大量封装:
方法 | 部分参数 | 作用 |
---|---|---|
offset(Date date, DateField dateField, int offset) | offset - 偏移量,正数为向后偏移,负数为向前偏移 | 获取指定日期偏移指定时间后的时间, 生成的偏移日期不影响原日期 |
offsetDay(Date date, int offset) | 偏移天 | |
offsetHour(Date date, int offset) | 偏移小时 | |
offsetMillisecond(Date date, int offset) | 偏移毫秒数 | |
offsetMinute(Date date, int offset) | 偏移分钟 | |
offsetMonth(Date date, int offset) | 偏移月 | |
offsetSecond(Date date, int offset) | 偏移秒数 | |
offsetWeek(Date date, int offset) | 偏移周 |
tring dateStr = "2022-11-09 22:33:23";
Date date = DateUtil.parse(dateStr);//结果:2022-11-11 22:33:23
Date newDate = DateUtil.offset(date, DateField.DAY_OF_MONTH, 2);//常用偏移,结果:2023-11-12 22:33:23
DateTime newDate2 = DateUtil.offsetDay(date, 3);//常用偏移,结果:22023-11-09 19:33:23
DateTime newDate3 = DateUtil.offsetHour(date, -3);
针对当前时间,提供了简化的偏移方法(例如昨天、上周、上个月等):
方法 | 部分参数 | 作用 |
---|---|---|
yesterday | 昨天 | |
tomorrow | 明天 | |
lastWeek | 上周 | |
nextWeek | 下周 | |
lastMonth | 上个月 | |
nextMonth | 下个月 |
2.4.3 计算两个时间之差
有时候我们需要计算两个日期之间的时间差(相差天数、相差小时数等等),Hutool将此类方法封装为between方法:
方法 | 部分参数 | 作用 |
---|---|---|
between(Date beginDate, Date endDate, DateUnit unit) | beginDate:起始日期 endDate:结束日期 unit:相差的单位 | 判断两个日期相差的时长,只保留绝对值 |
between(Date beginDate, Date endDate, DateUnit unit, boolean isAbs) | beginDate:起始日期 endDate:结束日期 unit:相差的单位 | 判断两个日期相差的时长 |
betweenMs(Date beginDate, Date endDate) | beginDate:起始日期 endDate:结束日期 | 判断两个日期相差的毫秒数 |
betweenDay(Date beginDate, Date endDate, boolean isReset) | beginDate:起始日期 endDate:结束日期 isReset:是否重置时间为起始时间 | 判断两个日期相差的天数。 |
betweenWeek(Date beginDate, Date endDate, boolean isReset) | beginDate:开始时间 endDate:结束时间 isReset:是否重置时间为起始时间 | 计算指定时间区间内的周数 |
betweenMonth | 计算两个日期相差月数。 | |
betweenYear | 计算两个日期相差年数。 |
String dateStr1 = "2022-11-09 22:33:23";
Date date1 = DateUtil.parse(dateStr1);String dateStr2 = "2022-12-09 23:33:23";
Date date2 = DateUtil.parse(dateStr2);// 相差一个月,31天
long betweenDay = DateUtil.between(date1, date2, DateUnit.DAY);Date startDate=DateUtil.parse("2021-04-20 02:00:00");
Date endDate=DateUtil.parse("2021-04-21 05:10:00");
long week=DateUtil.between(startDate,endDate,DateUnit.WEEK); //相差周数
long day=DateUtil.between(startDate,endDate,DateUnit.DAY); //相差天数
long hour=DateUtil.between(startDate,endDate,DateUnit.HOUR); //相差小时数
long minute=DateUtil.between(startDate,endDate,DateUnit.MINUTE);//相差分钟数
long second=DateUtil.between(startDate,endDate,DateUnit.SECOND);//相差秒数
long millis=DateUtil.between(startDate,endDate,DateUnit.MS); //相差毫秒数
2.5 日期解析
方法 | 部分参数 | 作用 |
---|---|---|
parse(CharSequence dateCharSequence) | 将日期字符串转换为 Date 对象 | |
parse(CharSequence dateStr, DateFormat dateFormat) | dateStr:Date字符串 dateFormat:格式化器 SimpleDateFormat | |
parse(CharSequence dateStr, DateParser parser) | dateStr:Date字符串 parser:格式化器 FastDateFormat | |
parse(CharSequence dateStr,DateParser parser,boolean lenient) | dateStr:Date字符串 parser:格式化器 FastDateFormat lenient:是否宽容模式 | |
parse(CharSequence dateStr, DateTimeFormatter formatter) | dateStr:Date字符串 formatter:格式化器 DateTimeFormatter | |
parse(CharSequence dateStr, String format) | dateStr:特定格式的日期 format:格式,例如yyyy-MM-dd | 将特定格式的日期转换为Date对象 |
parse(CharSequence dateStr, String format, Locale locale) | dateStr:特定格式的日期 format:格式,例如yyyy-MM-dd locale:区域信息 | 将特定格式的日期转换为Date对象 |
parse(String str, String… parsePatterns) | 通过给定的日期格式解析日期时间字符串 | |
parseDate(CharSequence dateCharSequence) | 解析日期字符串 | |
parseDateTime(CharSequence dateCharSequence) | 解析日期时间字符串 | |
parseLocalDateTime(CharSequence dateCharSequence) | 构建LocalDateTime对象 | |
parseTime(CharSequence dateCharSequence) | 解析时间,格式HH:mm:ss, | |
parseTimeToday(CharSequence dateCharSequence) | 解析时间,格式HH:mm或HH:mm:ss | |
parseUTC(String utcString) | 解析UTC时间 |
String dateStr = "2022-11-09";
Date date = DateUtil.parse(dateStr);Date date = DateUtil.parse(dateStr, "yyyy-MM-dd");
2.6 日期格式化
2.6.1 格式化日期时间
Hutool 对日期进行了非常详细的封装,可以有效避免我们自己的日期格式出现混乱的情况。而且 hutool 为我们提供了多个日期格式解析,转换成 yyyy-MM-dd HH:mm:ss
格式,同时我们可以引用这些日期格式:
方法 | 部分参数 | 作用 |
---|---|---|
format(Date date, DateFormat format) | 将 Date 对象格式化为指定的字符串 | |
format(Date date, String format) | 根据特定格式格式化日期 | |
formatChineseDate(Date date,boolean isUppercase,boolean withTime) | date - 被格式化的日期 isUppercase - 是否采用大写形式 withTime - 是否包含时间部分 | 格式化为中文日期格式。 |
formatDate(Date date) | 格式化日期部分(不包括时间) | |
formatDateTime(Date date) | 格式化日期时间 | |
formatHttpDate(Date date) | 格式化为Http的标准日期格式 | |
formatLocalDateTime | 格式化日期时间 | |
formatTime(Date date) | 格式化时间 |
String dateStr = "2023-11-09";
Date date = DateUtil.parse(dateStr);//结果 2017/03/01
String format = DateUtil.format(date, "yyyy/MM/dd");//常用格式的格式化,结果:2023-11-09
String formatDate = DateUtil.formatDate(date);//结果:2023-11-09 00:00:00
String formatDateTime = DateUtil.formatDateTime(date);//结果:00:00:00
String formatTime = DateUtil.formatTime(date);
2.6.2 格式化时间差
有时候我们希望看到易读的时间差,比如XX天XX小时XX分XX秒,此时使用DateUtil.formatBetween方法:
方法 | 部分参数 | 作用 |
---|---|---|
formatBetween(Date beginDate, Date endDate) | 格式化日期间隔输出,精确到毫秒 | |
formatBetween(Date beginDate, Date endDate, BetweenFormatter.Level level) | 格式化日期间隔输出 | |
formatBetween(long betweenMs) | 格式化日期间隔输出,精确到毫秒 | |
formatBetween(long betweenMs, BetweenFormatter.Level level) | 格式化日期间隔输出 |
【说明】BetweenFormatter 即格式化等级枚举,支持DAY(天)、HOUR(小时)、MILLISECOND(毫秒)、MINUTE(分钟)、SECOND(秒)等。
Date startDate=DateUtil.parse("2021-04-20 02:00:00");
Date endDate=DateUtil.parse("2021-04-21 05:10:00");//相差毫秒数
long millis=DateUtil.between(startDate,endDate,DateUnit.MS);
//相差1天(天)
String formatDay = DateUtil.formatBetween(millis, BetweenFormatter.Level.DAY);
//相差1天3小时(小时)
String formatHour = DateUtil.formatBetween(millis, BetweenFormatter.Level.HOUR);
//相差1天3小时10分(分钟)
String formatMinute = DateUtil.formatBetween(millis, BetweenFormatter.Level.MINUTE);
//相差1天3小时10分(秒)
String formatSecond = DateUtil.formatBetween(millis, BetweenFormatter.Level.SECOND);
//相差1天3小时10分(毫秒)
String formatMillis = DateUtil.formatBetween(millis, BetweenFormatter.Level.MILLISECOND);
2.7 其他
2.7.1 日期时间判断
Hutool 可以方便地判断日期是否在某个范围内、是否是周末等等。
方法 | 部分参数 | 作用 |
---|---|---|
boolean isAM(Date date) | 是否为上午 | |
boolean isLastDayOfMonth | 是否为本月最后一天 | |
boolean isLeapYear(int year) | 判断指定年份是否是闰年 | |
boolean isOverlap(Date realStartTime,Date realEndTime,Date startTime,Date endTime) | 检查两个时间段是否有时间重叠 | |
boolean isPM(Date date) | 是否为下午 | |
boolean isWeekend(Date date) | date - 判定的日期Date | 是否为周末(周六或周日) |
// 定义时间范围
Date startDate = DateUtil.parse("2025-04-01");
Date endDate = DateUtil.parse("2025-04-30");// 需要判断的日期
Date date = DateUtil.parse("2025-04-18");
// 判断日期是否在范围内
boolean isInRange = DateUtil.isIn(date, startDate, endDate);
System.out.println("isInRange = " + isInRange);// 判断是否是周末
boolean isWeekend = DateUtil.isWeekend(date);
System.out.println("日期是否是周末:" + isWeekend);
2.7.2 时间计时
方法 | 部分参数 | 作用 |
---|---|---|
String secondToTime(int seconds) | 秒数转为时间格式(HH:mm:ss) | |
long spendMs(long preTime) | 计时,常用于记录某段代码的执行时间,单位:毫秒 | |
long spendNt(long preTime) | 计时,常用于记录某段代码的执行时间,单位:纳秒 | |
timer() | 计算某个过程花费的时间,精确到毫秒 | |
timer(boolean isNano) | isNano - 是否使用纳秒计数,false则使用毫秒 | 计算某个过程花费的时间,精确到毫秒 |
int timeToSecond(String timeStr) | HH:mm:ss时间格式字符串转为秒数 |
三、总结
通过学习 Hutool 工具库中的 DateUtil 工具类,我们可以方便地处理日期和时间相关的操作。它提供了许多实用的方法,可以简化我们在日常开发中的日期处理工作,提高开发效率,减少出错的可能性。而且 DateUtil 在实现上进行了性能优化,对常见的日期和时间操作进行了高效处理,同时尽量避免了线程安全问题。
Hotool 不仅仅只有这一种工具类,还包含了其他许多工具类。在这里我作为一名Hutool的用户,我感谢Hutool的创作者和维护者们为我们带来如此强大便捷的工具库,希望Hutool功能越来越完善,为我们的开发工作带来更多的便利。同时也祝愿所有开发者没有BUG困扰,能够愉快地编写出高效、功能完善的程序。