add CalendarUtil

This commit is contained in:
Looly 2020-04-11 13:53:08 +08:00
parent bc486cdac4
commit 4a574e3241
5 changed files with 1238 additions and 1177 deletions

View File

@ -24,6 +24,7 @@
* 【json 】 解析Object中对是否为bean单独判断而不是直接解析
* 【core 】 SimHash锁改为StampedLock
* 【core 】 Singleton改为SimpleCache实现
* 【core 】 增加CalendarUtilDateUtil相关方法全部迁移到此
### Bug修复
* 【extra 】 修复SpringUtil使用devtools重启报错问题

View File

@ -0,0 +1,430 @@
package cn.hutool.core.date;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.util.StrUtil;
import java.time.Instant;
import java.time.LocalDateTime;
import java.util.Calendar;
import java.util.Date;
import java.util.LinkedHashSet;
/**
* 针对{@link Calendar} 对象封装工具类
*
* @author looly
* @since 5.3.0
*/
public class CalendarUtil {
/**
* 创建Calendar对象时间为默认时区的当前时间
*
* @return Calendar对象
* @since 4.6.6
*/
public static Calendar calendar() {
return Calendar.getInstance();
}
/**
* 转换为Calendar对象
*
* @param date 日期对象
* @return Calendar对象
*/
public static Calendar calendar(Date date) {
if (date instanceof DateTime) {
return ((DateTime) date).toCalendar();
} else {
return calendar(date.getTime());
}
}
/**
* 转换为Calendar对象
*
* @param millis 时间戳
* @return Calendar对象
*/
public static Calendar calendar(long millis) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(millis);
return cal;
}
/**
* 是否为上午
*
* @param calendar {@link Calendar}
* @return 是否为上午
*/
public static boolean isAM(Calendar calendar) {
return Calendar.AM == calendar.get(Calendar.AM_PM);
}
/**
* 是否为下午
*
* @param calendar {@link Calendar}
* @return 是否为下午
*/
public static boolean isPM(Calendar calendar) {
return Calendar.PM == calendar.get(Calendar.AM_PM);
}
/**
* 修改日期为某个时间字段起始时间
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @return {@link Calendar}
*/
public static Calendar truncate(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.TRUNCATE);
}
/**
* 修改日期为某个时间字段四舍五入时间
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @return {@link Calendar}
*/
public static Calendar round(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.ROUND);
}
/**
* 修改日期为某个时间字段结束时间
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @return {@link Calendar}
*/
public static Calendar ceiling(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.CEILING);
}
/**
* 获取秒级别的开始时间即忽略毫秒部分
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.6.2
*/
public static Calendar beginOfSecond(Calendar calendar) {
return truncate(calendar, DateField.SECOND);
}
/**
* 获取秒级别的结束时间即毫秒设置为999
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.6.2
*/
public static Calendar endOfSecond(Calendar calendar) {
return ceiling(calendar, DateField.SECOND);
}
/**
* 获取某天的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfDay(Calendar calendar) {
return truncate(calendar, DateField.DAY_OF_MONTH);
}
/**
* 获取某天的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfDay(Calendar calendar) {
return ceiling(calendar, DateField.DAY_OF_MONTH);
}
/**
* 获取给定日期当前周的开始时间周一定为一周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfWeek(Calendar calendar) {
return beginOfWeek(calendar, true);
}
/**
* 获取给定日期当前周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @param isMondayAsFirstDay 是否周一做为一周的第一天false表示周日做为第一天
* @return {@link Calendar}
* @since 3.1.2
*/
public static Calendar beginOfWeek(Calendar calendar, boolean isMondayAsFirstDay) {
calendar.setFirstDayOfWeek(isMondayAsFirstDay ? Calendar.MONDAY : Calendar.SUNDAY);
// WEEK_OF_MONTH为上限的字段不包括实际调整的为DAY_OF_MONTH
return truncate(calendar, DateField.WEEK_OF_MONTH);
}
/**
* 获取某周的结束时间周日定为一周的结束
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfWeek(Calendar calendar) {
return endOfWeek(calendar, true);
}
/**
* 获取某周的结束时间
*
* @param calendar 日期 {@link Calendar}
* @param isSundayAsLastDay 是否周日做为一周的最后一天false表示周六做为最后一天
* @return {@link Calendar}
*/
public static Calendar endOfWeek(Calendar calendar, boolean isSundayAsLastDay) {
calendar.setFirstDayOfWeek(isSundayAsLastDay ? Calendar.MONDAY : Calendar.SUNDAY);
// WEEK_OF_MONTH为上限的字段不包括实际调整的为DAY_OF_MONTH
return ceiling(calendar, DateField.WEEK_OF_MONTH);
}
/**
* 获取某月的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfMonth(Calendar calendar) {
return truncate(calendar, DateField.MONTH);
}
/**
* 获取某月的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfMonth(Calendar calendar) {
return ceiling(calendar, DateField.MONTH);
}
/**
* 获取某季度的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
public static Calendar beginOfQuarter(Calendar calendar) {
//noinspection MagicConstant
calendar.set(Calendar.MONTH, calendar.get(DateField.MONTH.getValue()) / 3 * 3);
calendar.set(Calendar.DAY_OF_MONTH, 1);
return beginOfDay(calendar);
}
/**
* 获取某季度的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
public static Calendar endOfQuarter(Calendar calendar) {
//noinspection MagicConstant
calendar.set(Calendar.MONTH, calendar.get(DateField.MONTH.getValue()) / 3 * 3 + 2);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return endOfDay(calendar);
}
/**
* 获取某年的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfYear(Calendar calendar) {
return truncate(calendar, DateField.YEAR);
}
/**
* 获取某年的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfYear(Calendar calendar) {
return ceiling(calendar, DateField.YEAR);
}
/**
* 比较两个日期是否为同一天
*
* @param cal1 日期1
* @param cal2 日期2
* @return 是否为同一天
*/
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && //
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && //
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA);
}
/**
* 获得指定日期区间内的年份和季节<br>
*
* @param startDate 起始日期包含
* @param endDate 结束日期包含
* @return 季度列表 元素类似于 20132
* @since 4.1.15
*/
public static LinkedHashSet<String> yearAndQuarter(long startDate, long endDate) {
LinkedHashSet<String> quarters = new LinkedHashSet<>();
final Calendar cal = calendar(startDate);
while (startDate <= endDate) {
// 如果开始时间超出结束时间让结束时间为开始时间处理完后结束循环
quarters.add(yearAndQuarter(cal));
cal.add(Calendar.MONTH, 3);
startDate = cal.getTimeInMillis();
}
return quarters;
}
/**
* 获得指定日期年份和季节<br>
* 格式[20131]表示2013年第一季度
*
* @param cal 日期
*/
public static String yearAndQuarter(Calendar cal) {
return StrUtil.builder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString();
}
/**
* 获取指定日期字段的最小值例如分钟的最小值是0
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最小值
* @see Calendar#getActualMinimum(int)
* @since 4.5.7
*/
public static int getBeginValue(Calendar calendar, int dateField) {
if (Calendar.DAY_OF_WEEK == dateField) {
return calendar.getFirstDayOfWeek();
}
return calendar.getActualMinimum(dateField);
}
/**
* 获取指定日期字段的最大值例如分钟的最大值是59
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最大值
* @see Calendar#getActualMaximum(int)
* @since 4.5.7
*/
public static int getEndValue(Calendar calendar, int dateField) {
if (Calendar.DAY_OF_WEEK == dateField) {
return (calendar.getFirstDayOfWeek() + 6) % 7;
}
return calendar.getActualMaximum(dateField);
}
/**
* Calendar{@link Instant}对象
*
* @param calendar Date对象
* @return {@link Instant}对象
* @since 5.0.5
*/
public static Instant toInstant(Calendar calendar) {
return null == calendar ? null : calendar.toInstant();
}
/**
* {@link Calendar} 转换为 {@link LocalDateTime}使用系统默认时区
*
* @param calendar {@link Calendar}
* @return {@link LocalDateTime}
* @since 5.0.5
*/
public static LocalDateTime toLocalDateTime(Calendar calendar) {
return LocalDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
}
/**
* {@code null}安全的{@link Calendar}比较{@code null}小于任何日期
*
* @param calendar1 日期1
* @param calendar2 日期2
* @return 比较结果如果calendar1 &lt; calendar2返回数小于0calendar1==calendar2返回0calendar1 &gt; calendar2 大于0
* @since 4.6.2
*/
public static int compare(Calendar calendar1, Calendar calendar2) {
return CompareUtil.compare(calendar1, calendar2);
}
/**
* 计算相对于dateToCompare的年龄长用于计算指定生日在某年的年龄
*
* @param birthday 生日
* @param dateToCompare 需要对比的日期
* @return 年龄
*/
public static int age(Calendar birthday, Calendar dateToCompare) {
return age(birthday.getTimeInMillis(), dateToCompare.getTimeInMillis());
}
/**
* 计算相对于dateToCompare的年龄长用于计算指定生日在某年的年龄
*
* @param birthday 生日
* @param dateToCompare 需要对比的日期
* @return 年龄
*/
protected static int age(long birthday, long dateToCompare) {
Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(dateToCompare);
if (cal.before(birthday)) {
throw new IllegalArgumentException("Birthday is after dateToCompare!");
}
final int year = cal.get(Calendar.YEAR);
final int month = cal.get(Calendar.MONTH);
final int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonth = dayOfMonth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.setTimeInMillis(birthday);
int age = year - cal.get(Calendar.YEAR);
final int monthBirth = cal.get(Calendar.MONTH);
if (month == monthBirth) {
final int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonthBirth = dayOfMonthBirth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
if ((false == isLastDayOfMonth || false == isLastDayOfMonthBirth) && dayOfMonth < dayOfMonthBirth) {
// 如果生日在当月但是未达到生日当天的日期年龄减一
age--;
}
} else if (month < monthBirth) {
// 如果当前月份未达到生日的月份年龄计算减一
age--;
}
return age;
}
}

View File

@ -3,10 +3,10 @@ package cn.hutool.core.date;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.comparator.CompareUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateModifier.ModifyType;
import cn.hutool.core.date.format.DateParser;
import cn.hutool.core.date.format.DatePrinter;
import cn.hutool.core.date.format.FastDateFormat;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.PatternPool;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ReUtil;
@ -39,7 +39,7 @@ import java.util.concurrent.TimeUnit;
*
* @author xiaoleilu
*/
public class DateUtil {
public class DateUtil extends CalendarUtil {
/**
* java.util.Date EEE MMM zzz 缩写数组
@ -129,42 +129,6 @@ public class DateUtil {
return new DateTime(temporalAccessor);
}
/**
* 创建Calendar对象时间为默认时区的当前时间
*
* @return Calendar对象
* @since 4.6.6
*/
public static Calendar calendar() {
return Calendar.getInstance();
}
/**
* 转换为Calendar对象
*
* @param date 日期对象
* @return Calendar对象
*/
public static Calendar calendar(Date date) {
if (date instanceof DateTime) {
return ((DateTime) date).toCalendar();
} else {
return calendar(date.getTime());
}
}
/**
* 转换为Calendar对象
*
* @param millis 时间戳
* @return Calendar对象
*/
public static Calendar calendar(long millis) {
final Calendar cal = Calendar.getInstance();
cal.setTimeInMillis(millis);
return cal;
}
/**
* 当前时间的时间戳
*
@ -359,17 +323,6 @@ public class DateUtil {
return DateTime.of(date).isAM();
}
/**
* 是否为上午
*
* @param calendar {@link Calendar}
* @return 是否为上午
* @since 4.5.7
*/
public static boolean isAM(Calendar calendar) {
return Calendar.AM == calendar.get(Calendar.AM_PM);
}
/**
* 是否为下午
*
@ -490,29 +443,6 @@ public class DateUtil {
}
return yearAndQuarter(startDate.getTime(), endDate.getTime());
}
/**
* 获得指定日期区间内的年份和季节<br>
*
* @param startDate 起始日期包含
* @param endDate 结束日期包含
* @return 季度列表 元素类似于 20132
* @since 4.1.15
*/
public static LinkedHashSet<String> yearAndQuarter(long startDate, long endDate) {
LinkedHashSet<String> quarters = new LinkedHashSet<>();
final Calendar cal = calendar(startDate);
while (startDate <= endDate) {
// 如果开始时间超出结束时间让结束时间为开始时间处理完后结束循环
quarters.add(yearAndQuarter(cal));
cal.add(Calendar.MONTH, 3);
startDate = cal.getTimeInMillis();
}
return quarters;
}
// ------------------------------------ Format start ----------------------------------------------
/**
@ -986,18 +916,6 @@ public class DateUtil {
return new DateTime(truncate(calendar(date), dateField));
}
/**
* 修改日期为某个时间字段起始时间
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @return {@link Calendar}
* @since 4.5.7
*/
public static Calendar truncate(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), ModifyType.TRUNCATE);
}
/**
* 修改日期为某个时间字段四舍五入时间
*
@ -1010,18 +928,6 @@ public class DateUtil {
return new DateTime(round(calendar(date), dateField));
}
/**
* 修改日期为某个时间字段四舍五入时间
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @return {@link Calendar}
* @since 4.5.7
*/
public static Calendar round(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), ModifyType.ROUND);
}
/**
* 修改日期为某个时间字段结束时间
*
@ -1034,18 +940,6 @@ public class DateUtil {
return new DateTime(ceiling(calendar(date), dateField));
}
/**
* 修改日期为某个时间字段结束时间
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @return {@link Calendar}
* @since 4.5.7
*/
public static Calendar ceiling(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), ModifyType.CEILING);
}
/**
* 获取秒级别的开始时间即忽略毫秒部分
*
@ -1068,28 +962,6 @@ public class DateUtil {
return new DateTime(endOfSecond(calendar(date)));
}
/**
* 获取秒级别的开始时间即忽略毫秒部分
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.6.2
*/
public static Calendar beginOfSecond(Calendar calendar) {
return truncate(calendar, DateField.SECOND);
}
/**
* 获取秒级别的结束时间即毫秒设置为999
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.6.2
*/
public static Calendar endOfSecond(Calendar calendar) {
return ceiling(calendar, DateField.SECOND);
}
/**
* 获取某天的开始时间
*
@ -1110,26 +982,6 @@ public class DateUtil {
return new DateTime(endOfDay(calendar(date)));
}
/**
* 获取某天的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfDay(Calendar calendar) {
return truncate(calendar, DateField.DAY_OF_MONTH);
}
/**
* 获取某天的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfDay(Calendar calendar) {
return ceiling(calendar, DateField.DAY_OF_MONTH);
}
/**
* 获取某周的开始时间周一定为一周的开始时间
*
@ -1150,54 +1002,6 @@ public class DateUtil {
return new DateTime(endOfWeek(calendar(date)));
}
/**
* 获取给定日期当前周的开始时间周一定为一周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfWeek(Calendar calendar) {
return beginOfWeek(calendar, true);
}
/**
* 获取给定日期当前周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @param isMondayAsFirstDay 是否周一做为一周的第一天false表示周日做为第一天
* @return {@link Calendar}
* @since 3.1.2
*/
public static Calendar beginOfWeek(Calendar calendar, boolean isMondayAsFirstDay) {
calendar.setFirstDayOfWeek(isMondayAsFirstDay ? Calendar.MONDAY : Calendar.SUNDAY);
// WEEK_OF_MONTH为上限的字段不包括实际调整的为DAY_OF_MONTH
return truncate(calendar, DateField.WEEK_OF_MONTH);
}
/**
* 获取某周的结束时间周日定为一周的结束
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfWeek(Calendar calendar) {
return endOfWeek(calendar, true);
}
/**
* 获取某周的结束时间
*
* @param calendar 日期 {@link Calendar}
* @param isSundayAsLastDay 是否周日做为一周的最后一天false表示周六做为最后一天
* @return {@link Calendar}
* @since 3.1.2
*/
public static Calendar endOfWeek(Calendar calendar, boolean isSundayAsLastDay) {
calendar.setFirstDayOfWeek(isSundayAsLastDay ? Calendar.MONDAY : Calendar.SUNDAY);
// WEEK_OF_MONTH为上限的字段不包括实际调整的为DAY_OF_MONTH
return ceiling(calendar, DateField.WEEK_OF_MONTH);
}
/**
* 获取某月的开始时间
*
@ -1218,26 +1022,6 @@ public class DateUtil {
return new DateTime(endOfMonth(calendar(date)));
}
/**
* 获取某月的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfMonth(Calendar calendar) {
return truncate(calendar, DateField.MONTH);
}
/**
* 获取某月的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfMonth(Calendar calendar) {
return ceiling(calendar, DateField.MONTH);
}
/**
* 获取某季度的开始时间
*
@ -1258,34 +1042,6 @@ public class DateUtil {
return new DateTime(endOfQuarter(calendar(date)));
}
/**
* 获取某季度的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
public static Calendar beginOfQuarter(Calendar calendar) {
//noinspection MagicConstant
calendar.set(Calendar.MONTH, calendar.get(DateField.MONTH.getValue()) / 3 * 3);
calendar.set(Calendar.DAY_OF_MONTH, 1);
return beginOfDay(calendar);
}
/**
* 获取某季度的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
* @since 4.1.0
*/
public static Calendar endOfQuarter(Calendar calendar) {
//noinspection MagicConstant
calendar.set(Calendar.MONTH, calendar.get(DateField.MONTH.getValue()) / 3 * 3 + 2);
calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
return endOfDay(calendar);
}
/**
* 获取某年的开始时间
*
@ -1305,27 +1061,6 @@ public class DateUtil {
public static DateTime endOfYear(Date date) {
return new DateTime(endOfYear(calendar(date)));
}
/**
* 获取某年的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar beginOfYear(Calendar calendar) {
return truncate(calendar, DateField.YEAR);
}
/**
* 获取某年的结束时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
*/
public static Calendar endOfYear(Calendar calendar) {
return ceiling(calendar, DateField.YEAR);
}
// --------------------------------------------------- Offset for now
/**
@ -1554,9 +1289,9 @@ public class DateUtil {
/**
* 计算指定指定时间区间内的周数
*
* @param beginDate 开始时间
* @param endDate 结束时间
* @param isReset 是否重置时间为起始时间
* @param beginDate 开始时间
* @param endDate 结束时间
* @param isReset 是否重置时间为起始时间
* @return 周数
*/
public static long betweenWeek(Date beginDate, Date endDate, boolean isReset) {
@ -1686,23 +1421,6 @@ public class DateUtil {
return isSameDay(calendar(date1), calendar(date2));
}
/**
* 比较两个日期是否为同一天
*
* @param cal1 日期1
* @param cal2 日期2
* @return 是否为同一天
* @since 4.1.13
*/
public static boolean isSameDay(Calendar cal1, Calendar cal2) {
if (cal1 == null || cal2 == null) {
throw new IllegalArgumentException("The date must not be null");
}
return cal1.get(Calendar.DAY_OF_YEAR) == cal2.get(Calendar.DAY_OF_YEAR) && //
cal1.get(Calendar.YEAR) == cal2.get(Calendar.YEAR) && //
cal1.get(Calendar.ERA) == cal2.get(Calendar.ERA);
}
/**
* 计时常用于记录某段代码的执行时间单位纳秒
*
@ -1863,41 +1581,16 @@ public class DateUtil {
/**
* 计算相对于dateToCompare的年龄长用于计算指定生日在某年的年龄
*
* @param birthDay 生日
* @param birthday 生日
* @param dateToCompare 需要对比的日期
* @return 年龄
*/
public static int age(Date birthDay, Date dateToCompare) {
Calendar cal = Calendar.getInstance();
cal.setTime(dateToCompare);
if (cal.before(birthDay)) {
throw new IllegalArgumentException(StrUtil.format("Birthday is after date {}!", formatDate(dateToCompare)));
public static int age(Date birthday, Date dateToCompare) {
Assert.notNull(birthday, "Birthday can not be null !");
if (null == dateToCompare) {
dateToCompare = date();
}
final int year = cal.get(Calendar.YEAR);
final int month = cal.get(Calendar.MONTH);
final int dayOfMonth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonth = dayOfMonth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
cal.setTime(birthDay);
int age = year - cal.get(Calendar.YEAR);
final int monthBirth = cal.get(Calendar.MONTH);
if (month == monthBirth) {
final int dayOfMonthBirth = cal.get(Calendar.DAY_OF_MONTH);
final boolean isLastDayOfMonthBirth = dayOfMonthBirth == cal.getActualMaximum(Calendar.DAY_OF_MONTH);
if ((false == isLastDayOfMonth || false == isLastDayOfMonthBirth) && dayOfMonth < dayOfMonthBirth) {
// 如果生日在当月但是未达到生日当天的日期年龄减一
age--;
}
} else if (month < monthBirth) {
// 如果当前月份未达到生日的月份年龄计算减一
age--;
}
return age;
return age(birthday.getTime(), dateToCompare.getTime());
}
/**
@ -2042,38 +1735,6 @@ public class DateUtil {
return Zodiac.getChineseZodiac(year);
}
/**
* 获取指定日期字段的最小值例如分钟的最小值是0
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最小值
* @see Calendar#getActualMinimum(int)
* @since 4.5.7
*/
public static int getBeginValue(Calendar calendar, int dateField) {
if (Calendar.DAY_OF_WEEK == dateField) {
return calendar.getFirstDayOfWeek();
}
return calendar.getActualMinimum(dateField);
}
/**
* 获取指定日期字段的最大值例如分钟的最大值是59
*
* @param calendar {@link Calendar}
* @param dateField {@link DateField}
* @return 字段最大值
* @see Calendar#getActualMaximum(int)
* @since 4.5.7
*/
public static int getEndValue(Calendar calendar, int dateField) {
if (Calendar.DAY_OF_WEEK == dateField) {
return (calendar.getFirstDayOfWeek() + 6) % 7;
}
return calendar.getActualMaximum(dateField);
}
/**
* {@code null}安全的日期比较{@code null}对象排在末尾
*
@ -2086,18 +1747,6 @@ public class DateUtil {
return CompareUtil.compare(date1, date2);
}
/**
* {@code null}安全的{@link Calendar}比较{@code null}小于任何日期
*
* @param calendar1 日期1
* @param calendar2 日期2
* @return 比较结果如果calendar1 &lt; calendar2返回数小于0calendar1==calendar2返回0calendar1 &gt; calendar2 大于0
* @since 4.6.2
*/
public static int compare(Calendar calendar1, Calendar calendar2) {
return CompareUtil.compare(calendar1, calendar2);
}
/**
* 纳秒转毫秒
*
@ -2131,17 +1780,6 @@ public class DateUtil {
return null == date ? null : date.toInstant();
}
/**
* Calendar{@link Instant}对象
*
* @param calendar Date对象
* @return {@link Instant}对象
* @since 5.0.5
*/
public static Instant toInstant(Calendar calendar) {
return null == calendar ? null : calendar.toInstant();
}
/**
* Date对象转换为{@link Instant}对象
*
@ -2189,21 +1827,10 @@ public class DateUtil {
return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
}
/**
* {@link Calendar} 转换为 {@link LocalDateTime}使用系统默认时区
*
* @param calendar {@link Calendar}
* @return {@link LocalDateTime}
* @since 5.0.5
*/
public static LocalDateTime toLocalDateTime(Calendar calendar) {
return LocalDateTime.ofInstant(calendar.toInstant(), calendar.getTimeZone().toZoneId());
}
/**
* {@link Date} 转换为 {@link LocalDateTime}使用系统默认时区
*
* @param date {@link Calendar}
* @param date {@link Date}
* @return {@link LocalDateTime}
* @since 5.0.5
*/
@ -2214,16 +1841,6 @@ public class DateUtil {
// ------------------------------------------------------------------------ Private method start
/**
* 获得指定日期年份和季节<br>
* 格式[20131]表示2013年第一季度
*
* @param cal 日期
*/
private static String yearAndQuarter(Calendar cal) {
return StrUtil.builder().append(cal.get(Calendar.YEAR)).append(cal.get(Calendar.MONTH) / 3 + 1).toString();
}
/**
* 标准化日期默认处理以空格区分的日期时间格式空格前为日期空格后为时间<br>
* 将以下字符替换为"-"

View File

@ -329,28 +329,36 @@ public class DateUtilTest {
Assert.assertEquals("20190321", ymd);
}
@SuppressWarnings("ConstantConditions")
@Test
public void parseTest5() {
// 测试时间解析
//noinspection ConstantConditions
String time = DateUtil.parse("22:12:12").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("22:12:12", time);
//noinspection ConstantConditions
time = DateUtil.parse("2:12:12").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("02:12:12", time);
//noinspection ConstantConditions
time = DateUtil.parse("2:2:12").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("02:02:12", time);
//noinspection ConstantConditions
time = DateUtil.parse("2:2:1").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("02:02:01", time);
//noinspection ConstantConditions
time = DateUtil.parse("22:2:1").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("22:02:01", time);
//noinspection ConstantConditions
time = DateUtil.parse("2:22:1").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("02:22:01", time);
// 测试两位时间解析
//noinspection ConstantConditions
time = DateUtil.parse("2:22").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("02:22:00", time);
//noinspection ConstantConditions
time = DateUtil.parse("12:22").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("12:22:00", time);
//noinspection ConstantConditions
time = DateUtil.parse("12:2").toString(DatePattern.NORM_TIME_FORMAT);
Assert.assertEquals("12:02:00", time);
@ -688,6 +696,14 @@ public class DateUtilTest {
Assert.assertEquals(18, age);
}
@Test(expected = IllegalArgumentException.class)
public void ageTest2(){
String d1 = "2019-02-29";
String d2 = "2018-02-28";
final int age = DateUtil.age(DateUtil.parseDate(d1), DateUtil.parseDate(d2));
Assert.assertEquals(18, age);
}
@Test
public void isExpiredTest(){
DateTime startDate = DateUtil.parse("2019-12-01 17:02:30");