From 5719c2815856668e34b28772d91bace54844668a Mon Sep 17 00:00:00 2001
From: Looly
Date: Mon, 28 Jun 2021 21:55:53 +0800
Subject: [PATCH] fix DateRange bug
---
CHANGELOG.md | 1 +
.../java/cn/hutool/core/date/DateRange.java | 13 ++--
.../java/cn/hutool/core/date/DateTime.java | 3 +-
.../java/cn/hutool/core/date/DateUtil.java | 2 +-
.../main/java/cn/hutool/core/lang/Range.java | 62 ++++++++++++-------
.../java/cn/hutool/core/lang/RangeTest.java | 31 +++++++---
6 files changed, 73 insertions(+), 39 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e8ab173e6..8ebd98e97 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -22,6 +22,7 @@
* 【core 】 修复IdcardUtil.getIdcardInfo.getProvinceCode获取为汉字的问题(issue#I3XP4Q@Gitee)
* 【core 】 修复CollUtil.subtract使用非标准Set等空指针问题(issue#I3XN1Z@Gitee)
* 【core 】 修复SqlFormatter部分SQL空指针问题(issue#I3XS44@Gitee)
+* 【core 】 修复DateRange计算问题(issue#I3Y1US@Gitee)
-------------------------------------------------------------------------------------------------------------
diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java b/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java
index 485205a03..432bfa3d4 100644
--- a/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java
+++ b/hutool-core/src/main/java/cn/hutool/core/date/DateRange.java
@@ -16,8 +16,8 @@ public class DateRange extends Range {
/**
* 构造,包含开始和结束日期时间
*
- * @param start 起始日期时间
- * @param end 结束日期时间
+ * @param start 起始日期时间(包括)
+ * @param end 结束日期时间(包括)
* @param unit 步进单位
*/
public DateRange(Date start, Date end, final DateField unit) {
@@ -27,8 +27,8 @@ public class DateRange extends Range {
/**
* 构造,包含开始和结束日期时间
*
- * @param start 起始日期时间
- * @param end 结束日期时间
+ * @param start 起始日期时间(包括)
+ * @param end 结束日期时间(包括)
* @param unit 步进单位
* @param step 步进数
*/
@@ -48,11 +48,12 @@ public class DateRange extends Range {
*/
public DateRange(Date start, Date end, final DateField unit, final int step, boolean isIncludeStart, boolean isIncludeEnd) {
super(DateUtil.date(start), DateUtil.date(end), (current, end1, index) -> {
- DateTime dt = current.offsetNew(unit, step);
+ final DateTime dt = DateUtil.date(start).offsetNew(unit, (index + 1) * step);
if (dt.isAfter(end1)) {
return null;
}
- return current.offsetNew(unit, step);
+
+ return dt;
}, isIncludeStart, isIncludeEnd);
}
diff --git a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java
index d210cd049..1fb76da0f 100644
--- a/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java
+++ b/hutool-core/src/main/java/cn/hutool/core/date/DateTime.java
@@ -329,8 +329,7 @@ public class DateTime extends Date {
//noinspection MagicConstant
cal.add(datePart.getValue(), offset);
- DateTime dt = ObjectUtil.clone(this);
- return dt.setTimeInternal(cal.getTimeInMillis());
+ return ObjectUtil.clone(this).setTimeInternal(cal.getTimeInMillis());
}
// -------------------------------------------------------------------- offset 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 0db1342ac..1d80f3a3a 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
@@ -1788,7 +1788,7 @@ public class DateUtil extends CalendarUtil {
/**
* 创建日期范围生成器
*
- * @param start 起始日期时间
+ * @param start 起始日期时间(包括)
* @param end 结束日期时间
* @param unit 步进单位
* @return {@link DateRange}
diff --git a/hutool-core/src/main/java/cn/hutool/core/lang/Range.java b/hutool-core/src/main/java/cn/hutool/core/lang/Range.java
index f24e309f4..4a7f1eb72 100644
--- a/hutool-core/src/main/java/cn/hutool/core/lang/Range.java
+++ b/hutool-core/src/main/java/cn/hutool/core/lang/Range.java
@@ -17,36 +17,53 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* 此类使用{@link ReentrantReadWriteLock}保证线程安全
*
*
- * @author Looly
- *
* @param 生成范围对象的类型
+ * @author Looly
*/
public class Range implements Iterable, Iterator, Serializable {
private static final long serialVersionUID = 1L;
- /** 锁保证线程安全 */
+ /**
+ * 锁保证线程安全
+ */
private Lock lock = new ReentrantLock();
- /** 起始对象 */
+ /**
+ * 起始对象
+ */
private final T start;
- /** 结束对象 */
+ /**
+ * 结束对象
+ */
private final T end;
- /** 当前对象 */
+ /**
+ * 当前对象
+ */
private T current;
- /** 下一个对象 */
+ /**
+ * 下一个对象
+ */
private T next;
- /** 步进 */
+ /**
+ * 步进
+ */
private final Steper steper;
- /** 索引 */
+ /**
+ * 索引
+ */
private int index = 0;
- /** 是否包含第一个元素 */
+ /**
+ * 是否包含第一个元素
+ */
private final boolean includeStart;
- /** 是否包含最后一个元素 */
+ /**
+ * 是否包含最后一个元素
+ */
private boolean includeEnd;
/**
* 构造
*
- * @param start 起始对象
+ * @param start 起始对象(包括)
* @param steper 步进
*/
public Range(T start, Steper steper) {
@@ -56,8 +73,8 @@ public class Range implements Iterable, Iterator, Serializable {
/**
* 构造
*
- * @param start 起始对象(包含)
- * @param end 结束对象(包含)
+ * @param start 起始对象(包含)
+ * @param end 结束对象(包含)
* @param steper 步进
*/
public Range(T start, T end, Steper steper) {
@@ -67,11 +84,11 @@ public class Range implements Iterable, Iterator, Serializable {
/**
* 构造
*
- * @param start 起始对象
- * @param end 结束对象
- * @param steper 步进
+ * @param start 起始对象
+ * @param end 结束对象
+ * @param steper 步进
* @param isIncludeStart 是否包含第一个元素
- * @param isIncludeEnd 是否包含最后一个元素
+ * @param isIncludeEnd 是否包含最后一个元素
*/
public Range(T start, T end, Steper steper, boolean isIncludeStart, boolean isIncludeEnd) {
this.start = start;
@@ -99,7 +116,7 @@ public class Range implements Iterable, Iterator, Serializable {
public boolean hasNext() {
lock.lock();
try {
- if(0 == this.index && this.includeStart) {
+ if (0 == this.index && this.includeStart) {
return true;
}
if (null == this.next) {
@@ -193,9 +210,8 @@ public class Range implements Iterable, Iterator, Serializable {
* 3、限制range个数,通过实现此接口,在实现类中定义一个对象属性,可灵活定义limit,限制range个数
*
*
- * @author Looly
- *
* @param 需要增加步进的对象
+ * @author Looly
*/
public interface Steper {
/**
@@ -204,8 +220,8 @@ public class Range implements Iterable, Iterator, Serializable {
* 用户需根据end参数自行定义边界,当达到边界时返回null表示结束,否则Range中边界对象无效,会导致无限循环
*
* @param current 上一次增加步进后的基础对象
- * @param end 结束对象
- * @param index 当前索引(步进到第几个元素),从0开始计数
+ * @param end 结束对象
+ * @param index 当前索引(步进到第几个元素),从0开始计数
* @return 增加步进后的对象
*/
T step(T current, T end, int index);
diff --git a/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java b/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java
index 474de5296..e7bd16180 100644
--- a/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java
+++ b/hutool-core/src/test/java/cn/hutool/core/lang/RangeTest.java
@@ -1,6 +1,7 @@
package cn.hutool.core.lang;
import cn.hutool.core.date.DateField;
+import cn.hutool.core.date.DateRange;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import org.junit.Assert;
@@ -12,30 +13,46 @@ import org.junit.Test;
*
*/
public class RangeTest {
-
+
@Test
public void dateRangeTest() {
DateTime start = DateUtil.parse("2017-01-01");
DateTime end = DateUtil.parse("2017-01-02");
-
+
final Range range = new Range<>(start, end, (current, end1, index) -> {
if (current.isAfterOrEquals(end1)) {
return null;
}
return current.offsetNew(DateField.DAY_OF_YEAR, 1);
});
-
+
Assert.assertTrue(range.hasNext());
- Assert.assertEquals(range.next(), DateUtil.parse("2017-01-01"));
+ Assert.assertEquals(DateUtil.parse("2017-01-01"), range.next());
Assert.assertTrue(range.hasNext());
- Assert.assertEquals(range.next(), DateUtil.parse("2017-01-02"));
+ Assert.assertEquals(DateUtil.parse("2017-01-02"), range.next());
Assert.assertFalse(range.hasNext());
}
-
+
+ @Test
+ public void dateRangeTest2() {
+ DateTime start = DateUtil.parse("2021-01-31");
+ DateTime end = DateUtil.parse("2021-03-31");
+
+ final DateRange range = DateUtil.range(start, end, DateField.MONTH);
+
+ Assert.assertTrue(range.hasNext());
+ Assert.assertEquals(DateUtil.parse("2021-01-31"), range.next());
+ Assert.assertTrue(range.hasNext());
+ Assert.assertEquals(DateUtil.parse("2021-02-28"), range.next());
+ Assert.assertTrue(range.hasNext());
+ Assert.assertEquals(DateUtil.parse("2021-03-31"), range.next());
+ Assert.assertFalse(range.hasNext());
+ }
+
@Test
public void intRangeTest() {
final Range range = new Range<>(1, 1, (current, end, index) -> current >= end ? null : current + 10);
-
+
Assert.assertTrue(range.hasNext());
Assert.assertEquals(Integer.valueOf(1), range.next());
Assert.assertFalse(range.hasNext());