ソースを参照

fix DateUtil.endOfYear

Looly 6 年 前
コミット
f26fad33cb

+ 3 - 0
CHANGELOG.md

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

+ 25 - 23
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
 

+ 18 - 6
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}对象,忽略毫秒部分
 	 * 
@@ -105,6 +105,16 @@ public class DateUtil {
 	}
 
 	/**
+	 * 创建Calendar对象,时间为默认时区的当前时间
+	 * 
+	 * @return Calendar对象
+	 * @since 4.6.6
+	 */
+	public static Calendar calendar() {
+		return Calendar.getInstance();
+	}
+
+	/**
 	 * 转换为Calendar对象
 	 * 
 	 * @param date 日期对象
@@ -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);
 	}
 

+ 39 - 39
hutool-core/src/main/java/cn/hutool/core/map/MapUtil.java

@@ -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);
-	}
 }

+ 9 - 8
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 <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.");
 		}
-		
+
 	}
 }

+ 1 - 2
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);

+ 10 - 0
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() {

+ 12 - 1
hutool-core/src/test/java/cn/hutool/core/date/DateUtilTest.java

@@ -478,11 +478,22 @@ public class DateUtilTest {
 	}
 
 	@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天

+ 0 - 13
hutool-core/src/test/java/cn/hutool/core/io/IoUtilTest.java

@@ -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);
-	}
-}