mirror of
https://gitee.com/chinabugotech/hutool.git
synced 2025-05-09 23:51:34 +08:00
fix DateUtil.endOfYear
This commit is contained in:
parent
aa12a8e408
commit
f26fad33cb
@ -6,7 +6,10 @@
|
||||
## 4.6.6
|
||||
|
||||
### 新特性
|
||||
* 【core】 MapUtil增加newConcurrentHashMap(pr#538@Github)
|
||||
|
||||
### Bug修复
|
||||
* 【core】 修复DateUtil.endOfYear计算错误问题(issuepr#540@Github)
|
||||
|
||||
-------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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.");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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() {
|
||||
|
@ -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天
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user