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());