add method

This commit is contained in:
Looly 2021-07-12 19:22:33 +08:00
parent 3160742be1
commit 0ed05e88ef
5 changed files with 142 additions and 53 deletions

View File

@ -6,6 +6,7 @@
# 5.7.5 (2021-07-12) # 5.7.5 (2021-07-12)
### 🐣新特性 ### 🐣新特性
* 【core 】 DateUtil增加ceiling重载可选是否归零毫秒
### 🐞Bug修复 ### 🐞Bug修复
* 【core 】 修复FileUtil.normalize处理上级路径的问题issue#I3YPEH@Gitee * 【core 】 修复FileUtil.normalize处理上级路径的问题issue#I3YPEH@Gitee

View File

@ -113,6 +113,23 @@ public class CalendarUtil {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.CEILING); return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.CEILING);
} }
/**
* 修改日期为某个时间字段结束时间<br>
* 可选是否归零毫秒
*
* <p>
* 有时候由于毫秒部分必须为0如MySQL数据库中因此在此加上选项
* </p>
*
* @param calendar {@link Calendar}
* @param dateField 时间字段
* @param truncateMillisecond 是否毫秒归零
* @return {@link Calendar}
*/
public static Calendar ceiling(Calendar calendar, DateField dateField, boolean truncateMillisecond) {
return DateModifier.modify(calendar, dateField.getValue(), DateModifier.ModifyType.CEILING, truncateMillisecond);
}
/** /**
* 获取秒级别的开始时间即忽略毫秒部分 * 获取秒级别的开始时间即忽略毫秒部分
* *
@ -655,9 +672,9 @@ public class CalendarUtil {
calendar.setLenient(lenient); calendar.setLenient(lenient);
for (final String parsePattern : parsePatterns) { for (final String parsePattern : parsePatterns) {
if(GlobalCustomFormat.isCustomFormat(parsePattern)){ if (GlobalCustomFormat.isCustomFormat(parsePattern)) {
final Date parse = GlobalCustomFormat.parse(str, parsePattern); final Date parse = GlobalCustomFormat.parse(str, parsePattern);
if(null == parse){ if (null == parse) {
continue; continue;
} }
calendar.setTime(parse); calendar.setTime(parse);

View File

@ -1,9 +1,9 @@
package cn.hutool.core.date; package cn.hutool.core.date;
import java.util.Calendar;
import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ArrayUtil;
import java.util.Calendar;
/** /**
* 日期修改器<br> * 日期修改器<br>
* 用于实现自定义某个日期字段的调整包括 * 用于实现自定义某个日期字段的调整包括
@ -15,12 +15,13 @@ import cn.hutool.core.util.ArrayUtil;
* </pre> * </pre>
* *
* @author looly * @author looly
*
*/ */
public class DateModifier { public class DateModifier {
/** 忽略的计算的字段 */ /**
private static final int[] IGNORE_FIELDS = new int[] { // * 忽略的计算的字段
*/
private static final int[] IGNORE_FIELDS = new int[]{ //
Calendar.HOUR_OF_DAY, // 与HOUR同名 Calendar.HOUR_OF_DAY, // 与HOUR同名
Calendar.AM_PM, // 此字段单独处理不参与计算起始和结束 Calendar.AM_PM, // 此字段单独处理不参与计算起始和结束
Calendar.DAY_OF_WEEK_IN_MONTH, // 不参与计算 Calendar.DAY_OF_WEEK_IN_MONTH, // 不参与计算
@ -32,36 +33,58 @@ public class DateModifier {
/** /**
* 修改日期 * 修改日期
* *
* @param calendar {@link Calendar} * @param calendar {@link Calendar}
* @param dateField 日期字段即保留到哪个日期字段 * @param dateField 日期字段即保留到哪个日期字段
* @param modifyType 修改类型包括舍去四舍五入进一等 * @param modifyType 修改类型包括舍去四舍五入进一等
* @return 修改后的{@link Calendar} * @return 修改后的{@link Calendar}
*/ */
public static Calendar modify(Calendar calendar, int dateField, ModifyType modifyType) { public static Calendar modify(Calendar calendar, int dateField, ModifyType modifyType) {
return modify(calendar, dateField, modifyType, false);
}
/**
* 修改日期取起始值或者结束值<br>
* 可选是否归零毫秒
*
* <p>
* {@link ModifyType#TRUNCATE}模式下毫秒始终要归零,
* 但是在{@link ModifyType#CEILING}{@link ModifyType#ROUND}模式下
* 有时候由于毫秒部分必须为0如MySQL数据库中因此在此加上选项
* </p>
*
* @param calendar {@link Calendar}
* @param dateField 日期字段即保留到哪个日期字段
* @param modifyType 修改类型包括舍去四舍五入进一等
* @param truncateMillisecond 是否归零毫秒
* @return 修改后的{@link Calendar}
* @since 5.7.5
*/
public static Calendar modify(Calendar calendar, int dateField, ModifyType modifyType, boolean truncateMillisecond) {
// AM_PM上下午特殊处理 // AM_PM上下午特殊处理
if (Calendar.AM_PM == dateField) { if (Calendar.AM_PM == dateField) {
boolean isAM = DateUtil.isAM(calendar); boolean isAM = DateUtil.isAM(calendar);
switch (modifyType) { switch (modifyType) {
case TRUNCATE: case TRUNCATE:
calendar.set(Calendar.HOUR_OF_DAY, isAM ? 0 : 12); calendar.set(Calendar.HOUR_OF_DAY, isAM ? 0 : 12);
break; break;
case CEILING: case CEILING:
calendar.set(Calendar.HOUR_OF_DAY, isAM ? 11 : 23); calendar.set(Calendar.HOUR_OF_DAY, isAM ? 11 : 23);
break; break;
case ROUND: case ROUND:
int min = isAM ? 0 : 12; int min = isAM ? 0 : 12;
int max = isAM ? 11 : 23; int max = isAM ? 11 : 23;
int href = (max - min) / 2 + 1; int href = (max - min) / 2 + 1;
int value = calendar.get(Calendar.HOUR_OF_DAY); int value = calendar.get(Calendar.HOUR_OF_DAY);
calendar.set(Calendar.HOUR_OF_DAY, (value < href) ? min : max); calendar.set(Calendar.HOUR_OF_DAY, (value < href) ? min : max);
break; break;
} }
// 处理下一级别字段 // 处理下一级别字段
return modify(calendar, dateField + 1, modifyType); return modify(calendar, dateField + 1, modifyType);
} }
final int endField = truncateMillisecond ? Calendar.SECOND : Calendar.MILLISECOND;
// 循环处理各级字段精确到毫秒字段 // 循环处理各级字段精确到毫秒字段
for (int i = dateField + 1; i <= Calendar.MILLISECOND; i++) { for (int i = dateField + 1; i <= endField; i++) {
if (ArrayUtil.contains(IGNORE_FIELDS, i)) { if (ArrayUtil.contains(IGNORE_FIELDS, i)) {
// 忽略无关字段WEEK_OF_MONTH始终不做修改 // 忽略无关字段WEEK_OF_MONTH始终不做修改
continue; continue;
@ -81,15 +104,21 @@ public class DateModifier {
modifyField(calendar, i, modifyType); modifyField(calendar, i, modifyType);
} }
if (truncateMillisecond) {
calendar.set(Calendar.MILLISECOND, 0);
}
return calendar; return calendar;
} }
// -------------------------------------------------------------------------------------------------- Private method start // -------------------------------------------------------------------------------------------------- Private method start
/** /**
* 修改日期字段值 * 修改日期字段值
* *
* @param calendar {@link Calendar} * @param calendar {@link Calendar}
* @param field 字段{@link Calendar} * @param field 字段{@link Calendar}
* @param modifyType {@link ModifyType} * @param modifyType {@link ModifyType}
*/ */
private static void modifyField(Calendar calendar, int field, ModifyType modifyType) { private static void modifyField(Calendar calendar, int field, ModifyType modifyType) {
@ -99,25 +128,25 @@ public class DateModifier {
} }
switch (modifyType) { switch (modifyType) {
case TRUNCATE: case TRUNCATE:
calendar.set(field, DateUtil.getBeginValue(calendar, field)); calendar.set(field, DateUtil.getBeginValue(calendar, field));
break; break;
case CEILING: case CEILING:
calendar.set(field, DateUtil.getEndValue(calendar, field)); calendar.set(field, DateUtil.getEndValue(calendar, field));
break; break;
case ROUND: case ROUND:
int min = DateUtil.getBeginValue(calendar, field); int min = DateUtil.getBeginValue(calendar, field);
int max = DateUtil.getEndValue(calendar, field); int max = DateUtil.getEndValue(calendar, field);
int href; int href;
if (Calendar.DAY_OF_WEEK == field) { if (Calendar.DAY_OF_WEEK == field) {
// 星期特殊处理假设周一是第一天中间的为周四 // 星期特殊处理假设周一是第一天中间的为周四
href = (min + 3) % 7; href = (min + 3) % 7;
} else { } else {
href = (max - min) / 2 + 1; href = (max - min) / 2 + 1;
} }
int value = calendar.get(field); int value = calendar.get(field);
calendar.set(field, (value < href) ? min : max); calendar.set(field, (value < href) ? min : max);
break; break;
} }
// Console.log("# {} -> {}", DateField.of(field), calendar.get(field)); // Console.log("# {} -> {}", DateField.of(field), calendar.get(field));
} }
@ -127,7 +156,6 @@ public class DateModifier {
* 修改类型 * 修改类型
* *
* @author looly * @author looly
*
*/ */
public enum ModifyType { public enum ModifyType {
/** /**

View File

@ -490,7 +490,7 @@ public class DateUtil extends CalendarUtil {
} }
// 检查自定义格式 // 检查自定义格式
if(GlobalCustomFormat.isCustomFormat(format)){ if (GlobalCustomFormat.isCustomFormat(format)) {
return GlobalCustomFormat.format(date, format); return GlobalCustomFormat.format(date, format);
} }
@ -702,7 +702,7 @@ public class DateUtil extends CalendarUtil {
* @since 4.5.18 * @since 4.5.18
*/ */
public static DateTime parse(CharSequence dateStr, String format, Locale locale) { public static DateTime parse(CharSequence dateStr, String format, Locale locale) {
if(GlobalCustomFormat.isCustomFormat(format)){ if (GlobalCustomFormat.isCustomFormat(format)) {
// 自定义格式化器忽略Locale // 自定义格式化器忽略Locale
return new DateTime(GlobalCustomFormat.parse(dateStr, format)); return new DateTime(GlobalCustomFormat.parse(dateStr, format));
} }
@ -828,7 +828,7 @@ public class DateUtil extends CalendarUtil {
} else if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) { } else if (length == DatePattern.UTC_SIMPLE_PATTERN.length() - 2) {
// 格式类似2018-09-13T05:34:31 // 格式类似2018-09-13T05:34:31
return parse(utcString, DatePattern.UTC_SIMPLE_FORMAT); return parse(utcString, DatePattern.UTC_SIMPLE_FORMAT);
} else if (StrUtil.contains(utcString, CharUtil.DOT)){ } else if (StrUtil.contains(utcString, CharUtil.DOT)) {
// 可能为 2021-03-17T06:31:33.99 // 可能为 2021-03-17T06:31:33.99
return parse(utcString, DatePattern.UTC_SIMPLE_MS_FORMAT); return parse(utcString, DatePattern.UTC_SIMPLE_MS_FORMAT);
} }
@ -983,7 +983,25 @@ public class DateUtil extends CalendarUtil {
} }
/** /**
* 获取秒级别的开始时间即忽略毫秒部分 * 修改日期为某个时间字段结束时间<br>
* 可选是否归零毫秒
*
* <p>
* 有时候由于毫秒部分必须为0如MySQL数据库中因此在此加上选项
* </p>
*
* @param date {@link Date}
* @param dateField 时间字段
* @param truncateMillisecond 是否毫秒归零
* @return {@link DateTime}
* @since 4.5.7
*/
public static DateTime ceiling(Date date, DateField dateField, boolean truncateMillisecond) {
return new DateTime(ceiling(calendar(date), dateField, truncateMillisecond));
}
/**
* 获取秒级别的开始时间即毫秒部分设置为0
* *
* @param date 日期 * @param date 日期
* @return {@link DateTime} * @return {@link DateTime}
@ -1847,13 +1865,12 @@ public class DateUtil extends CalendarUtil {
/** /**
* {@code null}安全的日期比较并只比较指定格式 {@code null}对象排在末尾, 并指定日期格式 * {@code null}安全的日期比较并只比较指定格式 {@code null}对象排在末尾, 并指定日期格式
* *
* * @param date1 日期1
* @param date1 日期1 * @param date2 日期2
* @param date2 日期2
* @param format 日期格式常用格式见 {@link DatePattern}; 允许为空 date1 date2; eg: yyyy-MM-dd * @param format 日期格式常用格式见 {@link DatePattern}; 允许为空 date1 date2; eg: yyyy-MM-dd
* @return 比较结果如果date1 &lt; date2返回数小于0date1==date2返回0date1 &gt; date2 大于0 * @return 比较结果如果date1 &lt; date2返回数小于0date1==date2返回0date1 &gt; date2 大于0
* @since 5.6.4
* @author dazer * @author dazer
* @since 5.6.4
*/ */
public static int compare(Date date1, Date date2, String format) { public static int compare(Date date1, Date date2, String format) {
if (format != null) { if (format != null) {

View File

@ -122,6 +122,32 @@ public class DateUtilTest {
Assert.assertEquals("2020-02-29 12:59:00", dateTime.toString()); Assert.assertEquals("2020-02-29 12:59:00", dateTime.toString());
} }
@Test
public void ceilingMinuteTest(){
String dateStr2 = "2020-02-29 12:59:34";
Date date2 = DateUtil.parse(dateStr2);
DateTime dateTime = DateUtil.ceiling(date2, DateField.MINUTE);
Assert.assertEquals("2020-02-29 12:59:59.999", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
dateTime = DateUtil.ceiling(date2, DateField.MINUTE, true);
Assert.assertEquals("2020-02-29 12:59:59.000", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
}
@Test
public void ceilingDayTest(){
String dateStr2 = "2020-02-29 12:59:34";
Date date2 = DateUtil.parse(dateStr2);
DateTime dateTime = DateUtil.ceiling(date2, DateField.DAY_OF_MONTH);
Assert.assertEquals("2020-02-29 23:59:59.999", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
dateTime = DateUtil.ceiling(date2, DateField.DAY_OF_MONTH, true);
Assert.assertEquals("2020-02-29 23:59:59.000", dateTime.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
}
@Test @Test
public void beginOfWeekTest() { public void beginOfWeekTest() {
String dateStr = "2017-03-01 22:33:23"; String dateStr = "2017-03-01 22:33:23";