fix DateUtil.endOfYear

This commit is contained in:
Looly 2019-09-15 14:32:00 +08:00
parent aa12a8e408
commit f26fad33cb
9 changed files with 117 additions and 92 deletions

View File

@ -6,7 +6,10 @@
## 4.6.6
### 新特性
* 【core】 MapUtil增加newConcurrentHashMappr#538@Github
### Bug修复
* 【core】 修复DateUtil.endOfYear计算错误问题issuepr#540@Github
-------------------------------------------------------------------------------------------------------------

View File

@ -19,13 +19,14 @@ import cn.hutool.core.util.ArrayUtil;
*/
public class DateModifier {
/** 忽略的字段 */
/** 忽略的计算的字段 */
private static final int[] ignoreFields = new int[] { //
Calendar.HOUR, //
Calendar.AM_PM, //
Calendar.DAY_OF_WEEK, //
Calendar.DAY_OF_YEAR, //
Calendar.WEEK_OF_YEAR//
Calendar.HOUR_OF_DAY, // 与HOUR同名
Calendar.AM_PM, // 此字段单独处理不参与计算起始和结束
Calendar.DAY_OF_WEEK_IN_MONTH, // 不参与计算
Calendar.DAY_OF_YEAR, // DAY_OF_MONTH体现
Calendar.WEEK_OF_MONTH, // 特殊处理
Calendar.WEEK_OF_YEAR // WEEK_OF_MONTH体现
};
/**
@ -37,7 +38,7 @@ public class DateModifier {
* @return 修改后的{@link Calendar}
*/
public static Calendar modify(Calendar calendar, int dateField, ModifyType modifyType) {
// 上下午特殊处理
// AM_PM上下午特殊处理
if (Calendar.AM_PM == dateField) {
boolean isAM = DateUtil.isAM(calendar);
switch (modifyType) {
@ -55,31 +56,27 @@ public class DateModifier {
calendar.set(Calendar.HOUR_OF_DAY, (value < href) ? min : max);
break;
}
}
// 当用户指定了无关字段时降级字段
if (ArrayUtil.contains(ignoreFields, dateField)) {
// 处理下一级别字段
return modify(calendar, dateField + 1, modifyType);
}
for (int i = Calendar.MILLISECOND; i > dateField; i--) {
if (ArrayUtil.contains(ignoreFields, i) || Calendar.WEEK_OF_MONTH == i) {
// 循环处理各级字段精确到毫秒字段
for (int i = dateField + 1; i <= Calendar.MILLISECOND; i++) {
if (ArrayUtil.contains(ignoreFields, i)) {
// 忽略无关字段WEEK_OF_MONTH始终不做修改
continue;
}
if (Calendar.WEEK_OF_MONTH == dateField) {
// 在星期模式下月的处理忽略之
// 在计算本周的起始和结束日时月相关的字段忽略
if (Calendar.WEEK_OF_MONTH == dateField || Calendar.WEEK_OF_YEAR == dateField) {
if (Calendar.DAY_OF_MONTH == i) {
continue;
} else if (Calendar.DAY_OF_WEEK_IN_MONTH == i) {
// 星期模式下星期几统一用DAY_OF_WEEK处理
i = Calendar.DAY_OF_WEEK;
}
} else if (Calendar.DAY_OF_WEEK_IN_MONTH == i) {
// 非星期模式下星期处理忽略之
// 由于DAY_OF_WEEK忽略自动降级到DAY_OF_WEEK_IN_MONTH
continue;
} else {
// 其它情况忽略周相关字段计算
if (Calendar.DAY_OF_WEEK == i) {
continue;
}
}
modifyField(calendar, i, modifyType);
@ -96,7 +93,11 @@ public class DateModifier {
* @param modifyType {@link ModifyType}
*/
private static void modifyField(Calendar calendar, int field, ModifyType modifyType) {
// Console.log("# {} {}", DateField.of(field), calendar.getActualMinimum(field));
if (Calendar.HOUR == field) {
// 修正小时HOUR为12小时制上午的结束时间为12:00此处改为HOUR_OF_DAY: 23:59
field = Calendar.HOUR_OF_DAY;
}
switch (modifyType) {
case TRUNCATE:
calendar.set(field, DateUtil.getBeginValue(calendar, field));
@ -118,6 +119,7 @@ public class DateModifier {
calendar.set(field, (value < href) ? min : max);
break;
}
// Console.log("# {} -> {}", DateField.of(field), calendar.get(field));
}
// -------------------------------------------------------------------------------------------------- Private method end

View File

@ -45,7 +45,7 @@ public class DateUtil {
public static DateTime date() {
return new DateTime();
}
/**
* 当前时间转换为{@link DateTime}对象忽略毫秒部分
*
@ -104,6 +104,16 @@ public class DateUtil {
return new DateTime(calendar);
}
/**
* 创建Calendar对象时间为默认时区的当前时间
*
* @return Calendar对象
* @since 4.6.6
*/
public static Calendar calendar() {
return Calendar.getInstance();
}
/**
* 转换为Calendar对象
*
@ -895,7 +905,7 @@ public class DateUtil {
public static Calendar ceiling(Calendar calendar, DateField dateField) {
return DateModifier.modify(calendar, dateField.getValue(), ModifyType.CEILING);
}
/**
* 获取秒级别的开始时间既忽略毫秒部分
*
@ -981,7 +991,7 @@ public class DateUtil {
}
/**
* 获取某周的开始时间
* 获取某周的开始时间周一定为一周的开始时间
*
* @param date 日期
* @return {@link DateTime}
@ -991,7 +1001,7 @@ public class DateUtil {
}
/**
* 获取某周的结束时间
* 获取某周的结束时间周日定为一周的结束
*
* @param date 日期
* @return {@link DateTime}
@ -1001,7 +1011,7 @@ public class DateUtil {
}
/**
* 获取周的开始时间
* 获取给定日期当前周的开始时间周一定为一周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @return {@link Calendar}
@ -1011,7 +1021,7 @@ public class DateUtil {
}
/**
* 获取某周的开始时间周一定为一周的开始时间
* 获取给定日期当前周的开始时间
*
* @param calendar 日期 {@link Calendar}
* @param isMondayAsFirstDay 是否周一做为一周的第一天false表示周日做为第一天
@ -1022,6 +1032,7 @@ public class DateUtil {
if (isMondayAsFirstDay) {
calendar.setFirstDayOfWeek(Calendar.MONDAY);
}
// WEEK_OF_MONTH为上限的字段不包括实际调整的为DAY_OF_MONTH
return truncate(calendar, DateField.WEEK_OF_MONTH);
}
@ -1047,6 +1058,7 @@ public class DateUtil {
if (isSundayAsLastDay) {
calendar.setFirstDayOfWeek(Calendar.MONDAY);
}
// WEEK_OF_MONTH为上限的字段不包括实际调整的为DAY_OF_MONTH
return ceiling(calendar, DateField.WEEK_OF_MONTH);
}

View File

@ -160,6 +160,45 @@ public class MapUtil {
public static <K, V> Map<K, V> newIdentityMap(int size) {
return new IdentityHashMap<>(size);
}
/**
* 新建一个初始容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY} 的ConcurrentHashMap
*
* @param <K> key的类型
* @param <V> value的类型
* @return ConcurrentHashMap
*/
public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap() {
return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
}
/**
* 新建一个ConcurrentHashMap
*
* @param size 初始容量当传入的容量小于等于0时容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY}
* @param <K> key的类型
* @param <V> value的类型
* @return ConcurrentHashMap
*/
public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(int size) {
final int initCapacity = size <= 0 ? DEFAULT_INITIAL_CAPACITY : size;
return new ConcurrentHashMap<>(initCapacity);
}
/**
* 传入一个Map将其转化为ConcurrentHashMap类型
*
* @param map map
* @param <K> key的类型
* @param <V> value的类型
* @return ConcurrentHashMap
*/
public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(Map<K, V> map) {
if(isEmpty(map)) {
return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
}
return new ConcurrentHashMap<>(map);
}
/**
* 创建Map<br>
@ -940,43 +979,4 @@ public class MapUtil {
return map;
}
/**
* 新建一个初始容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY} 的ConcurrentHashMap
*
* @param <K> key的类型
* @param <V> value的类型
* @return ConcurrentHashMap
*/
public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap() {
return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
}
/**
* 新建一个ConcurrentHashMap
*
* @param size 初始容量当传入的容量小于等于0时容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY}
* @param <K> key的类型
* @param <V> value的类型
* @return ConcurrentHashMap
*/
public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(int size) {
int initCapacity = size <= 0 ? DEFAULT_INITIAL_CAPACITY : size;
return new ConcurrentHashMap<>(initCapacity);
}
/**
* 传入一个Map将其转化为ConcurrentHashMap类型
*
* @param map map
* @param <K> key的类型
* @param <V> value的类型
* @return ConcurrentHashMap
*/
public static <K, V> ConcurrentHashMap<K, V> newConcurrentHashMap(Map<K, V> map) {
if(isEmpty(map)) {
return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY);
}
return new ConcurrentHashMap<>(map);
}
}

View File

@ -13,10 +13,11 @@ import cn.hutool.core.util.ArrayUtil;
/**
* 无重复键的Map
*
* @author looly
*
* @param <K>
* @param <V>
* @param <K> 键类型
* @param <V> 值类型
*/
public class TableMap<K, V> implements Map<K, V>, Serializable {
private static final long serialVersionUID = 1L;
@ -33,7 +34,7 @@ public class TableMap<K, V> implements Map<K, V>, Serializable {
this.keys = new ArrayList<>(size);
this.values = new ArrayList<>(size);
}
/**
* 构造
*
@ -119,17 +120,17 @@ public class TableMap<K, V> implements Map<K, V>, Serializable {
@Override
public Set<Map.Entry<K, V>> entrySet() {
HashSet<Map.Entry<K, V>> hashSet = new HashSet<>();
for(int i = 0; i < size(); i++) {
for (int i = 0; i < size(); i++) {
hashSet.add(new Entry<K, V>(keys.get(i), values.get(i)));
}
return hashSet;
}
private static class Entry<K, V> implements Map.Entry<K, V>{
private static class Entry<K, V> implements Map.Entry<K, V> {
private K key;
private V value;
public Entry(K key, V value) {
this.key = key;
this.value = value;
@ -149,6 +150,6 @@ public class TableMap<K, V> implements Map<K, V>, Serializable {
public V setValue(V value) {
throw new UnsupportedOperationException("setValue not supported.");
}
}
}

View File

@ -7,7 +7,6 @@ import org.junit.Assert;
import org.junit.Test;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Console;
/**
* 类型转换工具单元测试
@ -28,7 +27,7 @@ public class ConvertTest {
int a = 1;
long[] b = { 1, 2, 3, 4, 5 };
Console.log(Convert.convert(String.class, b));
Assert.assertEquals("[1, 2, 3, 4, 5]", Convert.convert(String.class, b));
String aStr = Convert.toStr(a);
Assert.assertEquals("1", aStr);

View File

@ -56,6 +56,16 @@ public class DateModifierTest {
begin = DateUtil.truncate(date, DateField.YEAR);
Assert.assertEquals("2017-01-01 00:00:00.000", begin.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
}
@Test
public void truncateDayOfWeekInMonthTest() {
String dateStr = "2017-03-01 22:33:23.123";
Date date = DateUtil.parse(dateStr);
// day of xxx按照day处理
DateTime begin = DateUtil.truncate(date, DateField.DAY_OF_WEEK_IN_MONTH);
Assert.assertEquals("2017-03-01 00:00:00.000", begin.toString(DatePattern.NORM_DATETIME_MS_PATTERN));
}
@Test
public void ceilingTest() {

View File

@ -477,12 +477,23 @@ public class DateUtilTest {
Assert.assertEquals("2019-05-16 17:57:18", time.toString());
}
@Test
public void endOfYearTest() {
DateTime date = DateUtil.date();
date.setField(DateField.YEAR, 2019);
DateTime endOfYear = DateUtil.endOfYear(date);
Assert.assertEquals("2019-12-31 23:59:59", endOfYear.toString());
}
@Test
public void endOfWeekTest() {
DateTime now = DateUtil.date();
// 周日
DateTime now = DateUtil.parse("2019-09-15 13:00");
DateTime startOfWeek = DateUtil.beginOfWeek(now);
Assert.assertEquals("2019-09-09 00:00:00", startOfWeek.toString());
DateTime endOfWeek = DateUtil.endOfWeek(now);
Assert.assertEquals("2019-09-15 23:59:59", endOfWeek.toString());
long between = DateUtil.between(endOfWeek, startOfWeek, DateUnit.DAY);
// 周一和周日相距6天

View File

@ -1,13 +0,0 @@
package cn.hutool.core.io;
import org.junit.Test;
import cn.hutool.core.lang.Console;
public class IoUtilTest {
@Test
public void moveTest() {
Console.log(2 << 14);
}
}