修复DateUtil.rangeContains未重置问题(issue#IB8OFS@gitee)

This commit is contained in:
Looly 2024-12-04 00:50:06 +08:00
parent 32331c2b23
commit 74e10f9547
5 changed files with 158 additions and 149 deletions

View File

@ -18,9 +18,9 @@ package org.dromara.hutool.core.date;
import org.dromara.hutool.core.collection.ListUtil; import org.dromara.hutool.core.collection.ListUtil;
import org.dromara.hutool.core.comparator.CompareUtil; import org.dromara.hutool.core.comparator.CompareUtil;
import org.dromara.hutool.core.date.format.DateFormatManager;
import org.dromara.hutool.core.date.format.DatePrinter; import org.dromara.hutool.core.date.format.DatePrinter;
import org.dromara.hutool.core.date.format.FastDateFormat; import org.dromara.hutool.core.date.format.FastDateFormat;
import org.dromara.hutool.core.date.format.DateFormatManager;
import org.dromara.hutool.core.date.format.parser.PositionDateParser; import org.dromara.hutool.core.date.format.parser.PositionDateParser;
import org.dromara.hutool.core.date.format.parser.RegisterDateParser; import org.dromara.hutool.core.date.format.parser.RegisterDateParser;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;

View File

@ -17,13 +17,10 @@
package org.dromara.hutool.core.lang.range; package org.dromara.hutool.core.lang.range;
import org.dromara.hutool.core.lang.Assert; import org.dromara.hutool.core.lang.Assert;
import org.dromara.hutool.core.thread.lock.NoLock;
import java.io.Serializable; import java.io.Serializable;
import java.util.Iterator; import java.util.Iterator;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.concurrent.locks.ReentrantReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock;
/** /**
@ -37,13 +34,9 @@ import java.util.concurrent.locks.ReentrantReadWriteLock;
* @param <T> 生成范围对象的类型 * @param <T> 生成范围对象的类型
* @author Looly * @author Looly
*/ */
public class Range<T> implements Iterable<T>, Iterator<T>, Serializable { public class Range<T> implements Iterable<T>, Serializable {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
/**
* 锁保证线程安全
*/
private Lock lock = new ReentrantLock();
/** /**
* 起始对象 * 起始对象
*/ */
@ -52,18 +45,11 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
* 结束对象 * 结束对象
*/ */
private final T end; private final T end;
/**
* 下一个对象
*/
private T next;
/** /**
* 步进 * 步进
*/ */
private final Stepper<T> stepper; private final Stepper<T> stepper;
/**
* 索引
*/
private int index = 0;
/** /**
* 是否包含第一个元素 * 是否包含第一个元素
*/ */
@ -108,51 +94,45 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
this.start = start; this.start = start;
this.end = end; this.end = end;
this.stepper = stepper; this.stepper = stepper;
this.next = safeStep(this.start);
this.includeStart = isIncludeStart; this.includeStart = isIncludeStart;
this.includeEnd = isIncludeEnd; this.includeEnd = isIncludeEnd;
} }
@Override
public Iterator<T> iterator() {
return new Iterator<T>(){
/** /**
* 禁用锁调用此方法后不再使用锁保护 * 下一个对象
*
* @return this
* @since 4.3.1
*/ */
public Range<T> disableLock() { private T next = safeStep(start);
this.lock = new NoLock(); /**
return this; * 索引
} */
private int index = 0;
@Override @Override
public boolean hasNext() { public boolean hasNext() {
lock.lock(); if (0 == this.index && includeStart) {
try {
if (0 == this.index && this.includeStart) {
return true; return true;
} }
if (null == this.next) { if (null == this.next) {
return false; return false;
} else if (!includeEnd && this.next.equals(this.end)) { } else {
return false; return includeEnd || !this.next.equals(end);
} }
} finally {
lock.unlock();
}
return true;
} }
@Override @Override
public T next() { public T next() {
lock.lock();
try {
if (!this.hasNext()) { if (!this.hasNext()) {
throw new NoSuchElementException("Has no next range!"); throw new NoSuchElementException("Has no next range!");
} }
return nextUncheck(); return nextUncheck();
} finally {
lock.unlock();
} }
@Override
public void remove() {
throw new UnsupportedOperationException("Can not remove ranged element!");
} }
/** /**
@ -162,7 +142,7 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
final T current; final T current;
if(0 == this.index){ if(0 == this.index){
current = start; current = start;
if(!this.includeStart){ if(!includeStart){
// 获取下一组元素 // 获取下一组元素
index ++; index ++;
return nextUncheck(); return nextUncheck();
@ -186,38 +166,14 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
final int index = this.index; final int index = this.index;
T next = null; T next = null;
try { try {
next = stepper.step(base, this.end, index); next = stepper.step(base, end, index);
} catch (final Exception e) { } catch (final Exception e) {
// ignore // ignore
} }
return next; return next;
} }
};
@Override
public void remove() {
throw new UnsupportedOperationException("Can not remove ranged element!");
}
@Override
public Iterator<T> iterator() {
return this;
}
/**
* 重置Range
*
* @return this
*/
public Range<T> reset() {
lock.lock();
try {
this.index = 0;
this.next = safeStep(this.start);
} finally {
lock.unlock();
}
return this;
} }
/** /**
@ -247,4 +203,9 @@ public class Range<T> implements Iterable<T>, Iterator<T>, Serializable {
*/ */
T step(T current, T end, int index); T step(T current, T end, int index);
} }
@Override
public String toString() {
return "Range [start=" + start + ", end=" + end + "]";
}
} }

View File

@ -25,6 +25,7 @@ import org.junit.jupiter.api.Test;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
import java.util.Iterator;
import java.util.List; import java.util.List;
public class Issue3081Test { public class Issue3081Test {
@ -35,10 +36,10 @@ public class Issue3081Test {
final Date end = DateUtil.parse("2023-04-25 00:00:00"); final Date end = DateUtil.parse("2023-04-25 00:00:00");
final DateRange dateTimes = new DateRange(start, end, DateField.DAY_OF_MONTH, 30, true, true); final DateRange dateTimes = new DateRange(start, end, DateField.DAY_OF_MONTH, 30, true, true);
final Iterator<DateTime> iterator = dateTimes.iterator();
final List<DateTime> dateTimeList = new ArrayList<>(); final List<DateTime> dateTimeList = new ArrayList<>();
while (dateTimes.hasNext()) { while (iterator.hasNext()) {
dateTimeList.add(dateTimes.next()); dateTimeList.add(iterator.next());
} }
Assertions.assertEquals(4, dateTimeList.size()); Assertions.assertEquals(4, dateTimeList.size());

View File

@ -0,0 +1,41 @@
/*
* Copyright (c) 2024 Hutool Team and hutool.cn
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.dromara.hutool.core.date;
import org.junit.jupiter.api.Test;
import java.util.List;
public class IssueIB8OFSTest {
@Test
void rangeTest() {
DateRange startRange = DateUtil.range(
DateUtil.parse("2017-01-01"),
DateUtil.parse("2017-01-31"), DateField.DAY_OF_YEAR);
DateRange endRange = DateUtil.range(
DateUtil.parse("2017-01-31"),
DateUtil.parse("2017-02-02"), DateField.DAY_OF_YEAR);
List<DateTime> dateTimes = DateUtil.rangeContains(startRange, endRange);
System.out.println("交集: ");
dateTimes.forEach(System.out::println);
List<DateTime> dateNotTimes = DateUtil.rangeNotContains(startRange, endRange);
System.out.println("差集: ");
dateNotTimes.forEach(System.out::println);
}
}

View File

@ -25,6 +25,7 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Date; import java.util.Date;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
@ -47,11 +48,12 @@ public class RangeTest {
return current.offsetNew(DateField.DAY_OF_YEAR, 1); return current.offsetNew(DateField.DAY_OF_YEAR, 1);
}); });
Assertions.assertTrue(range.hasNext()); final Iterator<DateTime> iterator = range.iterator();
Assertions.assertEquals(DateUtil.parse("2017-01-01"), range.next()); Assertions.assertTrue(iterator.hasNext());
Assertions.assertTrue(range.hasNext()); Assertions.assertEquals(DateUtil.parse("2017-01-01"), iterator.next());
Assertions.assertEquals(DateUtil.parse("2017-01-02"), range.next()); Assertions.assertTrue(iterator.hasNext());
Assertions.assertFalse(range.hasNext()); Assertions.assertEquals(DateUtil.parse("2017-01-02"), iterator.next());
Assertions.assertFalse(iterator.hasNext());
} }
@Test @Test
@ -86,23 +88,24 @@ public class RangeTest {
final Date end = DateUtil.parse("2021-03-31"); final Date end = DateUtil.parse("2021-03-31");
final DateRange range = DateUtil.range(start, end, DateField.MONTH); final DateRange range = DateUtil.range(start, end, DateField.MONTH);
final Iterator<DateTime> iterator = range.iterator();
Assertions.assertTrue(range.hasNext()); Assertions.assertTrue(iterator.hasNext());
Assertions.assertEquals(DateUtil.parse("2021-01-31"), range.next()); Assertions.assertEquals(DateUtil.parse("2021-01-31"), iterator.next());
Assertions.assertTrue(range.hasNext()); Assertions.assertTrue(iterator.hasNext());
Assertions.assertEquals(DateUtil.parse("2021-02-28"), range.next()); Assertions.assertEquals(DateUtil.parse("2021-02-28"), iterator.next());
Assertions.assertTrue(range.hasNext()); Assertions.assertTrue(iterator.hasNext());
Assertions.assertEquals(DateUtil.parse("2021-03-31"), range.next()); Assertions.assertEquals(DateUtil.parse("2021-03-31"), iterator.next());
Assertions.assertFalse(range.hasNext()); Assertions.assertFalse(iterator.hasNext());
} }
@Test @Test
public void intRangeTest() { public void intRangeTest() {
final Range<Integer> range = new Range<>(1, 1, (current, end, index) -> current >= end ? null : current + 10); final Range<Integer> range = new Range<>(1, 1, (current, end, index) -> current >= end ? null : current + 10);
final Iterator<Integer> iterator = range.iterator();
Assertions.assertTrue(range.hasNext()); Assertions.assertTrue(iterator.hasNext());
Assertions.assertEquals(Integer.valueOf(1), range.next()); Assertions.assertEquals(Integer.valueOf(1), iterator.next());
Assertions.assertFalse(range.hasNext()); Assertions.assertFalse(iterator.hasNext());
} }
@Test @Test
@ -112,19 +115,21 @@ public class RangeTest {
// 测试包含开始和结束情况下步进为1的情况 // 测试包含开始和结束情况下步进为1的情况
DateRange range = DateUtil.range(start, end, DateField.DAY_OF_YEAR); DateRange range = DateUtil.range(start, end, DateField.DAY_OF_YEAR);
Assertions.assertEquals(range.next(), DateUtil.parse("2017-01-01")); Iterator<DateTime> iterator = range.iterator();
Assertions.assertEquals(range.next(), DateUtil.parse("2017-01-02")); Assertions.assertEquals(iterator.next(), DateUtil.parse("2017-01-01"));
Assertions.assertEquals(range.next(), DateUtil.parse("2017-01-03")); Assertions.assertEquals(iterator.next(), DateUtil.parse("2017-01-02"));
Assertions.assertEquals(iterator.next(), DateUtil.parse("2017-01-03"));
try { try {
range.next(); iterator.next();
Assertions.fail("已超过边界,下一个元素不应该存在!"); Assertions.fail("已超过边界,下一个元素不应该存在!");
} catch (final NoSuchElementException ignored) { } catch (final NoSuchElementException ignored) {
} }
// 测试多步进的情况 // 测试多步进的情况
range = new DateRange(start, end, DateField.DAY_OF_YEAR, 2); range = new DateRange(start, end, DateField.DAY_OF_YEAR, 2);
Assertions.assertEquals(DateUtil.parse("2017-01-01"), range.next()); iterator = range.iterator();
Assertions.assertEquals(DateUtil.parse("2017-01-03"), range.next()); Assertions.assertEquals(DateUtil.parse("2017-01-01"), iterator.next());
Assertions.assertEquals(DateUtil.parse("2017-01-03"), iterator.next());
} }
@Test @Test
@ -134,11 +139,12 @@ public class RangeTest {
// 测试不包含开始结束时间的情况 // 测试不包含开始结束时间的情况
final DateRange range = new DateRange(start, end, DateField.DAY_OF_YEAR, 1, false, false); final DateRange range = new DateRange(start, end, DateField.DAY_OF_YEAR, 1, false, false);
Assertions.assertEquals(DateUtil.parse("2017-01-02"), range.next()); final Iterator<DateTime> iterator = range.iterator();
Assertions.assertEquals(DateUtil.parse("2017-01-03"), range.next()); Assertions.assertEquals(DateUtil.parse("2017-01-02"), iterator.next());
Assertions.assertEquals(DateUtil.parse("2017-01-04"), range.next()); Assertions.assertEquals(DateUtil.parse("2017-01-03"), iterator.next());
Assertions.assertEquals(DateUtil.parse("2017-01-04"), iterator.next());
try { try {
range.next(); iterator.next();
Assertions.fail("不包含结束时间情况下,下一个元素不应该存在!"); Assertions.fail("不包含结束时间情况下,下一个元素不应该存在!");
} catch (final NoSuchElementException ignored) { } catch (final NoSuchElementException ignored) {
} }