From f26fad33cb721263a60d2219b48994f153abd1f3 Mon Sep 17 00:00:00 2001 From: Looly Date: Sun, 15 Sep 2019 14:32:00 +0800 Subject: [PATCH] fix DateUtil.endOfYear --- CHANGELOG.md | 3 + .../cn/hutool/core/date/DateModifier.java | 48 ++++++------ .../java/cn/hutool/core/date/DateUtil.java | 24 ++++-- .../main/java/cn/hutool/core/map/MapUtil.java | 78 +++++++++---------- .../java/cn/hutool/core/map/TableMap.java | 17 ++-- .../cn/hutool/core/convert/ConvertTest.java | 3 +- .../cn/hutool/core/date/DateModifierTest.java | 10 +++ .../cn/hutool/core/date/DateUtilTest.java | 13 +++- .../java/cn/hutool/core/io/IoUtilTest.java | 13 ---- 9 files changed, 117 insertions(+), 92 deletions(-) delete mode 100644 hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java diff --git a/CHANGELOG.md b/CHANGELOG.md index cfb920bdf..f32c13d80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,10 @@ ## 4.6.6 ### 新特性 +* 【core】 MapUtil增加newConcurrentHashMap(pr#538@Github) + ### Bug修复 +* 【core】 修复DateUtil.endOfYear计算错误问题(issuepr#540@Github) ------------------------------------------------------------------------------------------------------------- diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java b/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java index 5709b95f6..449461c41 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateModifier.java @@ -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 diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java index ee836071e..8e0ab66d9 100644 --- a/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/date/DateUtil.java @@ -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); } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java index 4312f62eb..fb1197711 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java @@ -160,6 +160,45 @@ public class MapUtil { public static Map newIdentityMap(int size) { return new IdentityHashMap<>(size); } + + /** + * 新建一个初始容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY} 的ConcurrentHashMap + * + * @param key的类型 + * @param value的类型 + * @return ConcurrentHashMap + */ + public static ConcurrentHashMap newConcurrentHashMap() { + return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY); + } + + /** + * 新建一个ConcurrentHashMap + * + * @param size 初始容量,当传入的容量小于等于0时,容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY} + * @param key的类型 + * @param value的类型 + * @return ConcurrentHashMap + */ + public static ConcurrentHashMap newConcurrentHashMap(int size) { + final int initCapacity = size <= 0 ? DEFAULT_INITIAL_CAPACITY : size; + return new ConcurrentHashMap<>(initCapacity); + } + + /** + * 传入一个Map将其转化为ConcurrentHashMap类型 + * + * @param map map + * @param key的类型 + * @param value的类型 + * @return ConcurrentHashMap + */ + public static ConcurrentHashMap newConcurrentHashMap(Map map) { + if(isEmpty(map)) { + return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY); + } + return new ConcurrentHashMap<>(map); + } /** * 创建Map
@@ -940,43 +979,4 @@ public class MapUtil { return map; } - - /** - * 新建一个初始容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY} 的ConcurrentHashMap - * - * @param key的类型 - * @param value的类型 - * @return ConcurrentHashMap - */ - public static ConcurrentHashMap newConcurrentHashMap() { - return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY); - } - - /** - * 新建一个ConcurrentHashMap - * - * @param size 初始容量,当传入的容量小于等于0时,容量为{@link MapUtil#DEFAULT_INITIAL_CAPACITY} - * @param key的类型 - * @param value的类型 - * @return ConcurrentHashMap - */ - public static ConcurrentHashMap newConcurrentHashMap(int size) { - int initCapacity = size <= 0 ? DEFAULT_INITIAL_CAPACITY : size; - return new ConcurrentHashMap<>(initCapacity); - } - - /** - * 传入一个Map将其转化为ConcurrentHashMap类型 - * - * @param map map - * @param key的类型 - * @param value的类型 - * @return ConcurrentHashMap - */ - public static ConcurrentHashMap newConcurrentHashMap(Map map) { - if(isEmpty(map)) { - return new ConcurrentHashMap<>(DEFAULT_INITIAL_CAPACITY); - } - return new ConcurrentHashMap<>(map); - } } diff --git a/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java b/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java index e25a24716..11cfbb471 100644 --- a/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java +++ b/hutool-core/src/main/java/cn/hutool/core/map/TableMap.java @@ -13,10 +13,11 @@ import cn.hutool.core.util.ArrayUtil; /** * 无重复键的Map + * * @author looly * - * @param - * @param + * @param 键类型 + * @param 值类型 */ public class TableMap implements Map, Serializable { private static final long serialVersionUID = 1L; @@ -33,7 +34,7 @@ public class TableMap implements Map, Serializable { this.keys = new ArrayList<>(size); this.values = new ArrayList<>(size); } - + /** * 构造 * @@ -119,17 +120,17 @@ public class TableMap implements Map, Serializable { @Override public Set> entrySet() { HashSet> hashSet = new HashSet<>(); - for(int i = 0; i < size(); i++) { + for (int i = 0; i < size(); i++) { hashSet.add(new Entry(keys.get(i), values.get(i))); } return hashSet; } - private static class Entry implements Map.Entry{ - + private static class Entry implements Map.Entry { + 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 implements Map, Serializable { public V setValue(V value) { throw new UnsupportedOperationException("setValue not supported."); } - + } } diff --git a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java index c452b86c5..57736703c 100644 --- a/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/convert/ConvertTest.java @@ -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); diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateModifierTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateModifierTest.java index 5e700a6da..f0498c252 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateModifierTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateModifierTest.java @@ -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() { diff --git a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java index 9fe0e4253..57dee5f58 100644 --- a/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java +++ b/hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java @@ -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天 diff --git a/hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java b/hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java deleted file mode 100644 index 6b8543d79..000000000 --- a/hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java +++ /dev/null @@ -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); - } -}