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)
### 🐣新特性
* 【core 】 DateUtil增加ceiling重载可选是否归零毫秒
### 🐞Bug修复
* 【core 】 修复FileUtil.normalize处理上级路径的问题issue#I3YPEH@Gitee

View File

@ -113,6 +113,23 @@ public class CalendarUtil {
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);
for (final String parsePattern : parsePatterns) {
if(GlobalCustomFormat.isCustomFormat(parsePattern)){
if (GlobalCustomFormat.isCustomFormat(parsePattern)) {
final Date parse = GlobalCustomFormat.parse(str, parsePattern);
if(null == parse){
if (null == parse) {
continue;
}
calendar.setTime(parse);

View File

@ -1,9 +1,9 @@
package cn.hutool.core.date;
import java.util.Calendar;
import cn.hutool.core.util.ArrayUtil;
import java.util.Calendar;
/**
* 日期修改器<br>
* 用于实现自定义某个日期字段的调整包括
@ -15,12 +15,13 @@ import cn.hutool.core.util.ArrayUtil;
* </pre>
*
* @author looly
*
*/
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.AM_PM, // 此字段单独处理不参与计算起始和结束
Calendar.DAY_OF_WEEK_IN_MONTH, // 不参与计算
@ -32,36 +33,58 @@ public class DateModifier {
/**
* 修改日期
*
* @param calendar {@link Calendar}
* @param dateField 日期字段即保留到哪个日期字段
* @param calendar {@link Calendar}
* @param dateField 日期字段即保留到哪个日期字段
* @param modifyType 修改类型包括舍去四舍五入进一等
* @return 修改后的{@link Calendar}
*/
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上下午特殊处理
if (Calendar.AM_PM == dateField) {
boolean isAM = DateUtil.isAM(calendar);
switch (modifyType) {
case TRUNCATE:
calendar.set(Calendar.HOUR_OF_DAY, isAM ? 0 : 12);
break;
case CEILING:
calendar.set(Calendar.HOUR_OF_DAY, isAM ? 11 : 23);
break;
case ROUND:
int min = isAM ? 0 : 12;
int max = isAM ? 11 : 23;
int href = (max - min) / 2 + 1;
int value = calendar.get(Calendar.HOUR_OF_DAY);
calendar.set(Calendar.HOUR_OF_DAY, (value < href) ? min : max);
break;
case TRUNCATE:
calendar.set(Calendar.HOUR_OF_DAY, isAM ? 0 : 12);
break;
case CEILING:
calendar.set(Calendar.HOUR_OF_DAY, isAM ? 11 : 23);
break;
case ROUND:
int min = isAM ? 0 : 12;
int max = isAM ? 11 : 23;
int href = (max - min) / 2 + 1;
int value = calendar.get(Calendar.HOUR_OF_DAY);
calendar.set(Calendar.HOUR_OF_DAY, (value < href) ? min : max);
break;
}
// 处理下一级别字段
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)) {
// 忽略无关字段WEEK_OF_MONTH始终不做修改
continue;
@ -81,15 +104,21 @@ public class DateModifier {
modifyField(calendar, i, modifyType);
}
if (truncateMillisecond) {
calendar.set(Calendar.MILLISECOND, 0);
}
return calendar;
}
// -------------------------------------------------------------------------------------------------- Private method start
/**
* 修改日期字段值
*
* @param calendar {@link Calendar}
* @param field 字段{@link Calendar}
* @param calendar {@link Calendar}
* @param field 字段{@link Calendar}
* @param modifyType {@link ModifyType}
*/
private static void modifyField(Calendar calendar, int field, ModifyType modifyType) {
@ -99,25 +128,25 @@ public class DateModifier {
}
switch (modifyType) {
case TRUNCATE:
calendar.set(field, DateUtil.getBeginValue(calendar, field));
break;
case CEILING:
calendar.set(field, DateUtil.getEndValue(calendar, field));
break;
case ROUND:
int min = DateUtil.getBeginValue(calendar, field);
int max = DateUtil.getEndValue(calendar, field);
int href;
if (Calendar.DAY_OF_WEEK == field) {
// 星期特殊处理假设周一是第一天中间的为周四
href = (min + 3) % 7;
} else {
href = (max - min) / 2 + 1;
}
int value = calendar.get(field);
calendar.set(field, (value < href) ? min : max);
break;
case TRUNCATE:
calendar.set(field, DateUtil.getBeginValue(calendar, field));
break;
case CEILING:
calendar.set(field, DateUtil.getEndValue(calendar, field));
break;
case ROUND:
int min = DateUtil.getBeginValue(calendar, field);
int max = DateUtil.getEndValue(calendar, field);
int href;
if (Calendar.DAY_OF_WEEK == field) {
// 星期特殊处理假设周一是第一天中间的为周四
href = (min + 3) % 7;
} else {
href = (max - min) / 2 + 1;
}
int value = calendar.get(field);
calendar.set(field, (value < href) ? min : max);
break;
}
// Console.log("# {} -> {}", DateField.of(field), calendar.get(field));
}
@ -127,7 +156,6 @@ public class DateModifier {
* 修改类型
*
* @author looly
*
*/
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);
}
@ -702,7 +702,7 @@ public class DateUtil extends CalendarUtil {
* @since 4.5.18
*/
public static DateTime parse(CharSequence dateStr, String format, Locale locale) {
if(GlobalCustomFormat.isCustomFormat(format)){
if (GlobalCustomFormat.isCustomFormat(format)) {
// 自定义格式化器忽略Locale
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) {
// 格式类似2018-09-13T05:34:31
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
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 日期
* @return {@link DateTime}
@ -1847,13 +1865,12 @@ public class DateUtil extends CalendarUtil {
/**
* {@code null}安全的日期比较并只比较指定格式 {@code null}对象排在末尾, 并指定日期格式
*
*
* @param date1 日期1
* @param date2 日期2
* @param date1 日期1
* @param date2 日期2
* @param format 日期格式常用格式见 {@link DatePattern}; 允许为空 date1 date2; eg: yyyy-MM-dd
* @return 比较结果如果date1 &lt; date2返回数小于0date1==date2返回0date1 &gt; date2 大于0
* @since 5.6.4
* @author dazer
* @since 5.6.4
*/
public static int compare(Date date1, Date date2, String format) {
if (format != null) {

View File

@ -122,6 +122,32 @@ public class DateUtilTest {
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
public void beginOfWeekTest() {
String dateStr = "2017-03-01 22:33:23";