检查月份或日期或年份是否在字符串格式的两个日期范围内
Check if month or day or year is in range of two dates in string format
但现在我意识到我可以有更多案例来解决这个问题。
我有一个过滤器,它是一个字符串,只能接受 3 种日期格式 - YYYY
、YYYY-MM
、YYYY-MM-DD
。
我想检查请求的字符串是否在两个字符串值日期的范围内。
比方说,我有两个日期字符串,可以是上述 3 种日期格式中的任何一种
用例 1
开始日期:2010-05-15
& 结束日期:2020-05
。
以下所有requested String
都在结果范围内:
2010
、2020
、2010-05
、2020-05
、2020-05-22
、2010-05-15
、2010-05-22
、2015-02-25
下面的所有 requested String
不 在
范围内
2009
, 2021
, 2010-04
, 2020-06
, 2010-05-14
, 2020-06-01
用例 2
开始日期:2010
& 结束日期:2020-05-15
以下所有值都在结果范围内:
2010
、2020
、2010-05
、2020-05
、2010-05-22
、2010-01-01
、2020-05-15
、2015-02-25
以下所有值 不 在
范围内
2009
、2021
、2020-06
、2020-05-16
、2020-06-01
用例 3
开始日期:NULL
& 结束日期:2020-05
2020-05-31
之前的所有请求日期都在结果范围内:
2020-05-31
之后的所有值都不在范围内。
用例 4
开始日期:2010-05-15
& 结束日期:NULL
在 2010-05-15
之后 的所有请求日期都在结果范围内:
2010-05-15
之前的所有值都不在范围内。
我正在使用 Java 时间来检查日期是在给定日期之前还是之后,但在我的例子中,我有一个字符串作为请求日期、开始日期和结束日期,它可能是采用 3 种日期格式中的任何一种。
我不确定这是否是一个有效的解决方案,但这就是我的想法
只需将所有日期(请求日期、开始日期和结束日期)分解为数字并将请求年份与开始和结束年份进行比较,如果请求日期中的月份可用且开始和结束日期也可用,则比较是否月份在范围内,日期也一样。
有人可以帮忙解决这个问题吗?
Date min, max; // assume these are set to something
Date d; // the date in question
return d.after(min) && d.before(max);
将所有字符串输入转换为 LocalDate
个对象
别再用字符串思考了。这些字符串仅用于用户界面和将值序列化到存储。当您的应用程序是 运行 时,您应该使用对象执行您的逻辑,java.time 个对象,最终 LocalDate
。
将所有输入转换为 LocalDate
。
检查输入的长度。
if( input.length() = 4 ) {…}
如果输入长度为4个字符,则解析为Year
. Trap for exception thrown in case faulty input gets past your filter. From the year, get a LocalDate
by calling atDay
。
try{
Year year = Year.parse( "2020" ) ;
LocalDate ld = year.atDay( 1 ) ;
} catch ( DateTimeParseException e ) {
…
}
如果输入是七个字符,则解析为 YearMonth
。通过 atDay
方法获得 LocalDate
的表单。
try{
YearMonth YearMonth = YearMonth.parse( "2020-05" ) ;
LocalDate ld = yearMonth.atDay( 1 ) ;
} catch ( DateTimeParseException e ) {
…
}
如果输入是 10 个字符,则解析为 LocalDate
。
try{
LocalDate localDate = LocalDate.parse( "2020-05-23" ) ;
} catch ( DateTimeParseException e ) {
…
}
所有 LocalDate
对象就位后,进行比较。在定义时间跨度时始终使用半开放方法。开头包含,结尾不包含。
提示:“不早于”是询问“等于或晚于”的简写方式。
( ! target.isBefore( start ) ) && target.isBefore( stop )
由于您的日期采用 yyyy-MM-dd
格式,您应该能够执行字符串比较,确保只比较相同长度的字符串(注意比较不同日期的规则长度):
private static boolean isDateInRange(String startDate, String endDate, String date) {
return (null == startDate || compareDateString(startDate, date) <= 0)
&& (null == endDate || compareDateString(date, endDate) <= 0);
}
private static int compareDateString(String date1, String date2) {
if (date1.length() == date2.length())
return date1.compareTo(date2);
int length = Math.min(date1.length(), date2.length());
return date1.substring(0, length).compareTo(date2.substring(0, length));
}
您可以通过以下方式查看:
String startDate = "2010-05-15";
String endDate = "2020-05";
String date = "2020-06";
boolean inRange = isDateInRange(startDate, endDate, date);
简洁明了,因此您应该使用它,但它之所以有效,是因为日期格式是简单的 ISO-8601 文本。如果格式不同,您需要先解析它们,然后才能比较它们。这里有一个解析字符串的方案,当然逻辑会比较复杂。
我将从创建一个助手开始 class:
/**
* Class for storing a {@code Temporal} of varying precision,
* {@code Year}, {@code YearMonth}, or {@code LocalDate}.
*/
class DynamicTemporal {
private enum Precision {
YEAR {
@Override
protected int compare(Temporal a, Temporal b) {
return widen(a).compareTo(widen(b));
}
private Year widen(Temporal value) {
return Year.from(value);
}
},
MONTH {
@Override
protected int compare(Temporal a, Temporal b) {
return widen(a).compareTo(widen(b));
}
private YearMonth widen(Temporal value) {
return YearMonth.from(value);
}
},
DAY {
@Override
protected int compare(Temporal a, Temporal b) {
return widen(a).compareTo(widen(b));
}
private LocalDate widen(Temporal value) {
return (LocalDate) value;
}
};
protected abstract int compare(Temporal a, Temporal b);
}
private final Temporal value;
private final Precision precision;
public static DynamicTemporal parse(String text) {
if (text == null || text.equals("NULL"))
return null;
if (text.length() >= 10)
return new DynamicTemporal(LocalDate.parse(text), Precision.DAY);
if (text.length() >= 7)
return new DynamicTemporal(YearMonth.parse(text), Precision.MONTH);
return new DynamicTemporal(Year.parse(text), Precision.YEAR);
}
private DynamicTemporal(Temporal value, Precision precision) {
this.value = value;
this.precision = precision;
}
public int compareTo(DynamicTemporal other) {
Precision effectivePrecision = (this.precision.compareTo(other.precision) <= 0 ? this.precision : other.precision);
return effectivePrecision.compare(this.value, other.value);
}
}
现在您可以轻松实现isDateInRange()
方法:
private static boolean isDateInRange(String start, String end, String date) {
DynamicTemporal dateTemporal = DynamicTemporal.parse(date);
DynamicTemporal startTemporal = DynamicTemporal.parse(start);
DynamicTemporal endTemporal = DynamicTemporal.parse(end);
if (startTemporal != null && dateTemporal.compareTo(startTemporal) < 0)
return false; // date is before start
if (endTemporal != null && dateTemporal.compareTo(endTemporal) > 0)
return false; // date is after end
return true;
}
测试(来自问题)
public static void main(String[] args) {
test("2010-05-15", "2020-05", true, "2010", "2020", "2010-05", "2020-05", "2020-05-22", "2010-05-15", "2010-05-22", "2015-02-25");
test("2010-05-15", "2020-05", false, "2009", "2021", "2010-04", "2020-06", "2010-05-14", "2020-06-01");
test("2010", "2020-05-15", true, "2010", "2020", "2010-05", "2020-05", "2010-05-22", "2010-01-01", "2020-05-15", "2015-02-25");
test("2010", "2020-05-15", false, "2009", "2021", "2020-06", "2020-05-16", "2020-06-01");
test("NULL", "2020-05", true, "2020-05-31", "2020-05", "2020", "2020-05-30", "2020-04", "2019");
test("NULL", "2020-05", false, "2020-06-01", "2020-06", "2021", "2020-06-02", "2020-07", "2022");
test("2010-05-15", "NULL", true, "2010-05-15", "2010-05", "2010", "2010-05-16", "2010-06", "2011");
test("2010-05-15", "NULL", false, "2010-05-14", "2010-04", "2009", "2010-05-13", "2010-03", "2008");
}
private static void test(String start, String end, boolean expected, String... dates) {
for (String date : dates) {
boolean actual = isDateInRange(start, end, date);
System.out.printf("isDateInRange(%-10s, %-10s, %-10s) = %-5s %s%n",
start, end, date, actual, (actual == expected ? "OK" : "FAILED!"));
}
}
输出
isDateInRange(2010-05-15, 2020-05 , 2010 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2020 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2010-05 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2020-05 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2020-05-22) = true OK
isDateInRange(2010-05-15, 2020-05 , 2010-05-15) = true OK
isDateInRange(2010-05-15, 2020-05 , 2010-05-22) = true OK
isDateInRange(2010-05-15, 2020-05 , 2015-02-25) = true OK
isDateInRange(2010-05-15, 2020-05 , 2009 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2021 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2010-04 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2020-06 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2010-05-14) = false OK
isDateInRange(2010-05-15, 2020-05 , 2020-06-01) = false OK
isDateInRange(2010 , 2020-05-15, 2010 ) = true OK
isDateInRange(2010 , 2020-05-15, 2020 ) = true OK
isDateInRange(2010 , 2020-05-15, 2010-05 ) = true OK
isDateInRange(2010 , 2020-05-15, 2020-05 ) = true OK
isDateInRange(2010 , 2020-05-15, 2010-05-22) = true OK
isDateInRange(2010 , 2020-05-15, 2010-01-01) = true OK
isDateInRange(2010 , 2020-05-15, 2020-05-15) = true OK
isDateInRange(2010 , 2020-05-15, 2015-02-25) = true OK
isDateInRange(2010 , 2020-05-15, 2009 ) = false OK
isDateInRange(2010 , 2020-05-15, 2021 ) = false OK
isDateInRange(2010 , 2020-05-15, 2020-06 ) = false OK
isDateInRange(2010 , 2020-05-15, 2020-05-16) = false OK
isDateInRange(2010 , 2020-05-15, 2020-06-01) = false OK
isDateInRange(NULL , 2020-05 , 2020-05-31) = true OK
isDateInRange(NULL , 2020-05 , 2020-05 ) = true OK
isDateInRange(NULL , 2020-05 , 2020 ) = true OK
isDateInRange(NULL , 2020-05 , 2020-05-30) = true OK
isDateInRange(NULL , 2020-05 , 2020-04 ) = true OK
isDateInRange(NULL , 2020-05 , 2019 ) = true OK
isDateInRange(NULL , 2020-05 , 2020-06-01) = false OK
isDateInRange(NULL , 2020-05 , 2020-06 ) = false OK
isDateInRange(NULL , 2020-05 , 2021 ) = false OK
isDateInRange(NULL , 2020-05 , 2020-06-02) = false OK
isDateInRange(NULL , 2020-05 , 2020-07 ) = false OK
isDateInRange(NULL , 2020-05 , 2022 ) = false OK
isDateInRange(2010-05-15, NULL , 2010-05-15) = true OK
isDateInRange(2010-05-15, NULL , 2010-05 ) = true OK
isDateInRange(2010-05-15, NULL , 2010 ) = true OK
isDateInRange(2010-05-15, NULL , 2010-05-16) = true OK
isDateInRange(2010-05-15, NULL , 2010-06 ) = true OK
isDateInRange(2010-05-15, NULL , 2011 ) = true OK
isDateInRange(2010-05-15, NULL , 2010-05-14) = false OK
isDateInRange(2010-05-15, NULL , 2010-04 ) = false OK
isDateInRange(2010-05-15, NULL , 2009 ) = false OK
isDateInRange(2010-05-15, NULL , 2010-05-13) = false OK
isDateInRange(2010-05-15, NULL , 2010-03 ) = false OK
isDateInRange(2010-05-15, NULL , 2008 ) = false OK
将所有内容转换为日期范围。将日期范围表示为从开始日期到结束日期不包括 的半开间隔。并将开始日期和结束日期表示为两个 LocalDate
对象。
例如,从您的用例 1
Start date: 2010-05-15
& end date: 2020-05
作为日期范围,这变为 从 2010-05-15(含)到 2020-06-01(不含)。
要测试 2010 是否在范围内,请将 2010 转换为 从 2010-01-01 到 2011-01-01 exclusive 的范围。现在,当且仅当这两个范围重叠时,2010 年才在范围内。当且仅当第一个起始日期早于第二个日期 和 第二个起始日期早于第一个日期时,他们才会这样做。使用 LocalDate.isBefore()
。我们需要“strict before”,而这个方法正好给了我们这个。由于 2010-05-15 在 2011-01-01 和 之前 2010-01-01 在 2020-06-01 之前,范围重叠,因此我们得出结论 2010 在范围内.
案例1的另一个例子,为了测试2010-05-14是否在同一范围内,将其转换为范围从2010-05-14到2010-05-15(不包括) 。查看 2010-05-15 是否早于 2010-05-15 和 2010-05-14 是否早于 2020-06-01。前半部分已经是假的,所以我们断定日期不在范围内。
实施说明:我可能会使用此格式化程序来解析您的所有字符串:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu[-MM[-dd]]");
您可以使用此格式化程序的 parseBest
方法从您提到的任何字符串中获取 LocalDate
、YearMonth
或 Year
。在每种情况下,您都可以从那里转换。
Link: Determine Whether Two Date Ranges Overlap
I am not sure if this is a valid solution but this is what I am
thinking
Simply break all the dates (requested, start, & end) into numbers and
compare requested year with years in start & end, if months in
requested date is available and also available in the start and end
then compare if the month is in range, and same for the dates.
是的,你的方法是有效的。 java.time 中的 类 没有提供完美的支持,但是使用低级 TemporalAccessor
接口有一个方法:
class IsInRangeWithMissingFields {
@Test
void useCase1() {
assertTrue(isInRange("2010-05-15", "2020-05", "2010"));
assertTrue(isInRange("2010-05-15", "2020-05", "2020"));
assertTrue(isInRange("2010-05-15", "2020-05", "2010-05"));
assertTrue(isInRange("2010-05-15", "2020-05", "2020-05"));
assertTrue(isInRange("2010-05-15", "2020-05", "2020-05-22"));
assertTrue(isInRange("2010-05-15", "2020-05", "2010-05-15"));
assertTrue(isInRange("2010-05-15", "2020-05", "2010-05-22"));
assertTrue(isInRange("2010-05-15", "2020-05", "2015-02-25"));
assertFalse(isInRange("2010-05-15", "2020-05", "2009"));
assertFalse(isInRange("2010-05-15", "2020-05", "2021"));
assertFalse(isInRange("2010-05-15", "2020-05", "2010-04"));
assertFalse(isInRange("2010-05-15", "2020-05", "2020-06"));
assertFalse(isInRange("2010-05-15", "2020-05", "2010-05-14"));
assertFalse(isInRange("2010-05-15", "2020-05", "2020-06-01"));
}
@Test
void useCase2() {
assertTrue(isInRange("2010", "2020-05-15", "2010"));
assertTrue(isInRange("2010", "2020-05-15", "2020"));
assertTrue(isInRange("2010", "2020-05-15", "2010-05"));
assertTrue(isInRange("2010", "2020-05-15", "2020-05"));
assertTrue(isInRange("2010", "2020-05-15", "2010-05-22"));
assertTrue(isInRange("2010", "2020-05-15", "2010-01-01"));
assertTrue(isInRange("2010", "2020-05-15", "2020-05-15"));
assertTrue(isInRange("2010", "2020-05-15", "2015-02-25"));
assertFalse(isInRange("2010", "2020-05-15", "2009"));
assertFalse(isInRange("2010", "2020-05-15", "2021"));
assertFalse(isInRange("2010", "2020-05-15", "2020-06"));
assertFalse(isInRange("2010", "2020-05-15", "2020-05-16"));
assertFalse(isInRange("2010", "2020-05-15", "2020-06-01"));
}
@Test
void useCase3() {
assertTrue(isInRange(null, "2020-05", "2020-05-31"));
assertFalse(isInRange(null, "2020-05", "2020-06-01"));
}
@Test
void useCase4() {
assertTrue(isInRange("2010-05-15", null, "2010-05-15"));
assertFalse(isInRange("2010-05-15", null, "2010-05-14"));
}
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu[-MM[-dd]]");
public static boolean isInRange(String startStr, String endStr, String requestStr) {
TemporalAccessor request = formatter.parse(requestStr);
// is request before start?
if (startStr != null) {
TemporalAccessor start = formatter.parse(startStr);
if (request.get(ChronoField.YEAR)
< start.get(ChronoField.YEAR)) {
return false;
}
if (request.get(ChronoField.YEAR)
== start.get(ChronoField.YEAR)) {
if (request.isSupported(ChronoField.MONTH_OF_YEAR)
&& start.isSupported(ChronoField.MONTH_OF_YEAR)) {
if (request.get(ChronoField.MONTH_OF_YEAR)
< start.get(ChronoField.MONTH_OF_YEAR)) {
return false;
}
if (request.get(ChronoField.MONTH_OF_YEAR)
== start.get(ChronoField.MONTH_OF_YEAR)) {
if (request.isSupported(ChronoField.DAY_OF_MONTH)
&& start.isSupported(ChronoField.DAY_OF_MONTH)) {
if (request.get(ChronoField.DAY_OF_MONTH)
< start.get(ChronoField.DAY_OF_MONTH)) {
return false;
}
}
}
}
}
}
// is request after end?
if (endStr != null) {
TemporalAccessor end = formatter.parse(endStr);
if (request.get(ChronoField.YEAR) > end.get(ChronoField.YEAR)) {
return false;
}
if (request.get(ChronoField.YEAR) == end.get(ChronoField.YEAR)) {
if (request.isSupported(ChronoField.MONTH_OF_YEAR)
&& end.isSupported(ChronoField.MONTH_OF_YEAR)) {
if (request.get(ChronoField.MONTH_OF_YEAR)
> end.get(ChronoField.MONTH_OF_YEAR)) {
return false;
}
if (request.get(ChronoField.MONTH_OF_YEAR)
== end.get(ChronoField.MONTH_OF_YEAR)) {
if (request.isSupported(ChronoField.DAY_OF_MONTH)
&& end.isSupported(ChronoField.DAY_OF_MONTH)) {
if (request.get(ChronoField.DAY_OF_MONTH)
> end.get(ChronoField.DAY_OF_MONTH)) {
return false;
}
}
}
}
}
}
return true;
}
}
此单元测试在我的计算机上运行时出现绿色障碍。
我有一个过滤器,它是一个字符串,只能接受 3 种日期格式 - YYYY
、YYYY-MM
、YYYY-MM-DD
。
我想检查请求的字符串是否在两个字符串值日期的范围内。
比方说,我有两个日期字符串,可以是上述 3 种日期格式中的任何一种
用例 1
开始日期:2010-05-15
& 结束日期:2020-05
。
以下所有requested String
都在结果范围内:
2010
、2020
、2010-05
、2020-05
、2020-05-22
、2010-05-15
、2010-05-22
、2015-02-25
下面的所有 requested String
不 在
2009
, 2021
, 2010-04
, 2020-06
, 2010-05-14
, 2020-06-01
用例 2
开始日期:2010
& 结束日期:2020-05-15
以下所有值都在结果范围内:
2010
、2020
、2010-05
、2020-05
、2010-05-22
、2010-01-01
、2020-05-15
、2015-02-25
以下所有值 不 在
范围内2009
、2021
、2020-06
、2020-05-16
、2020-06-01
用例 3
开始日期:NULL
& 结束日期:2020-05
2020-05-31
之前的所有请求日期都在结果范围内:
2020-05-31
之后的所有值都不在范围内。
用例 4
开始日期:2010-05-15
& 结束日期:NULL
在 2010-05-15
之后 的所有请求日期都在结果范围内:
2010-05-15
之前的所有值都不在范围内。
我正在使用 Java 时间来检查日期是在给定日期之前还是之后,但在我的例子中,我有一个字符串作为请求日期、开始日期和结束日期,它可能是采用 3 种日期格式中的任何一种。
我不确定这是否是一个有效的解决方案,但这就是我的想法
只需将所有日期(请求日期、开始日期和结束日期)分解为数字并将请求年份与开始和结束年份进行比较,如果请求日期中的月份可用且开始和结束日期也可用,则比较是否月份在范围内,日期也一样。
有人可以帮忙解决这个问题吗?
Date min, max; // assume these are set to something
Date d; // the date in question
return d.after(min) && d.before(max);
将所有字符串输入转换为 LocalDate
个对象
别再用字符串思考了。这些字符串仅用于用户界面和将值序列化到存储。当您的应用程序是 运行 时,您应该使用对象执行您的逻辑,java.time 个对象,最终 LocalDate
。
将所有输入转换为 LocalDate
。
检查输入的长度。
if( input.length() = 4 ) {…}
如果输入长度为4个字符,则解析为Year
. Trap for exception thrown in case faulty input gets past your filter. From the year, get a LocalDate
by calling atDay
。
try{
Year year = Year.parse( "2020" ) ;
LocalDate ld = year.atDay( 1 ) ;
} catch ( DateTimeParseException e ) {
…
}
如果输入是七个字符,则解析为 YearMonth
。通过 atDay
方法获得 LocalDate
的表单。
try{
YearMonth YearMonth = YearMonth.parse( "2020-05" ) ;
LocalDate ld = yearMonth.atDay( 1 ) ;
} catch ( DateTimeParseException e ) {
…
}
如果输入是 10 个字符,则解析为 LocalDate
。
try{
LocalDate localDate = LocalDate.parse( "2020-05-23" ) ;
} catch ( DateTimeParseException e ) {
…
}
所有 LocalDate
对象就位后,进行比较。在定义时间跨度时始终使用半开放方法。开头包含,结尾不包含。
提示:“不早于”是询问“等于或晚于”的简写方式。
( ! target.isBefore( start ) ) && target.isBefore( stop )
由于您的日期采用 yyyy-MM-dd
格式,您应该能够执行字符串比较,确保只比较相同长度的字符串(注意比较不同日期的规则长度):
private static boolean isDateInRange(String startDate, String endDate, String date) {
return (null == startDate || compareDateString(startDate, date) <= 0)
&& (null == endDate || compareDateString(date, endDate) <= 0);
}
private static int compareDateString(String date1, String date2) {
if (date1.length() == date2.length())
return date1.compareTo(date2);
int length = Math.min(date1.length(), date2.length());
return date1.substring(0, length).compareTo(date2.substring(0, length));
}
您可以通过以下方式查看:
String startDate = "2010-05-15";
String endDate = "2020-05";
String date = "2020-06";
boolean inRange = isDateInRange(startDate, endDate, date);
我将从创建一个助手开始 class:
/**
* Class for storing a {@code Temporal} of varying precision,
* {@code Year}, {@code YearMonth}, or {@code LocalDate}.
*/
class DynamicTemporal {
private enum Precision {
YEAR {
@Override
protected int compare(Temporal a, Temporal b) {
return widen(a).compareTo(widen(b));
}
private Year widen(Temporal value) {
return Year.from(value);
}
},
MONTH {
@Override
protected int compare(Temporal a, Temporal b) {
return widen(a).compareTo(widen(b));
}
private YearMonth widen(Temporal value) {
return YearMonth.from(value);
}
},
DAY {
@Override
protected int compare(Temporal a, Temporal b) {
return widen(a).compareTo(widen(b));
}
private LocalDate widen(Temporal value) {
return (LocalDate) value;
}
};
protected abstract int compare(Temporal a, Temporal b);
}
private final Temporal value;
private final Precision precision;
public static DynamicTemporal parse(String text) {
if (text == null || text.equals("NULL"))
return null;
if (text.length() >= 10)
return new DynamicTemporal(LocalDate.parse(text), Precision.DAY);
if (text.length() >= 7)
return new DynamicTemporal(YearMonth.parse(text), Precision.MONTH);
return new DynamicTemporal(Year.parse(text), Precision.YEAR);
}
private DynamicTemporal(Temporal value, Precision precision) {
this.value = value;
this.precision = precision;
}
public int compareTo(DynamicTemporal other) {
Precision effectivePrecision = (this.precision.compareTo(other.precision) <= 0 ? this.precision : other.precision);
return effectivePrecision.compare(this.value, other.value);
}
}
现在您可以轻松实现isDateInRange()
方法:
private static boolean isDateInRange(String start, String end, String date) {
DynamicTemporal dateTemporal = DynamicTemporal.parse(date);
DynamicTemporal startTemporal = DynamicTemporal.parse(start);
DynamicTemporal endTemporal = DynamicTemporal.parse(end);
if (startTemporal != null && dateTemporal.compareTo(startTemporal) < 0)
return false; // date is before start
if (endTemporal != null && dateTemporal.compareTo(endTemporal) > 0)
return false; // date is after end
return true;
}
测试(来自问题)
public static void main(String[] args) {
test("2010-05-15", "2020-05", true, "2010", "2020", "2010-05", "2020-05", "2020-05-22", "2010-05-15", "2010-05-22", "2015-02-25");
test("2010-05-15", "2020-05", false, "2009", "2021", "2010-04", "2020-06", "2010-05-14", "2020-06-01");
test("2010", "2020-05-15", true, "2010", "2020", "2010-05", "2020-05", "2010-05-22", "2010-01-01", "2020-05-15", "2015-02-25");
test("2010", "2020-05-15", false, "2009", "2021", "2020-06", "2020-05-16", "2020-06-01");
test("NULL", "2020-05", true, "2020-05-31", "2020-05", "2020", "2020-05-30", "2020-04", "2019");
test("NULL", "2020-05", false, "2020-06-01", "2020-06", "2021", "2020-06-02", "2020-07", "2022");
test("2010-05-15", "NULL", true, "2010-05-15", "2010-05", "2010", "2010-05-16", "2010-06", "2011");
test("2010-05-15", "NULL", false, "2010-05-14", "2010-04", "2009", "2010-05-13", "2010-03", "2008");
}
private static void test(String start, String end, boolean expected, String... dates) {
for (String date : dates) {
boolean actual = isDateInRange(start, end, date);
System.out.printf("isDateInRange(%-10s, %-10s, %-10s) = %-5s %s%n",
start, end, date, actual, (actual == expected ? "OK" : "FAILED!"));
}
}
输出
isDateInRange(2010-05-15, 2020-05 , 2010 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2020 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2010-05 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2020-05 ) = true OK
isDateInRange(2010-05-15, 2020-05 , 2020-05-22) = true OK
isDateInRange(2010-05-15, 2020-05 , 2010-05-15) = true OK
isDateInRange(2010-05-15, 2020-05 , 2010-05-22) = true OK
isDateInRange(2010-05-15, 2020-05 , 2015-02-25) = true OK
isDateInRange(2010-05-15, 2020-05 , 2009 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2021 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2010-04 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2020-06 ) = false OK
isDateInRange(2010-05-15, 2020-05 , 2010-05-14) = false OK
isDateInRange(2010-05-15, 2020-05 , 2020-06-01) = false OK
isDateInRange(2010 , 2020-05-15, 2010 ) = true OK
isDateInRange(2010 , 2020-05-15, 2020 ) = true OK
isDateInRange(2010 , 2020-05-15, 2010-05 ) = true OK
isDateInRange(2010 , 2020-05-15, 2020-05 ) = true OK
isDateInRange(2010 , 2020-05-15, 2010-05-22) = true OK
isDateInRange(2010 , 2020-05-15, 2010-01-01) = true OK
isDateInRange(2010 , 2020-05-15, 2020-05-15) = true OK
isDateInRange(2010 , 2020-05-15, 2015-02-25) = true OK
isDateInRange(2010 , 2020-05-15, 2009 ) = false OK
isDateInRange(2010 , 2020-05-15, 2021 ) = false OK
isDateInRange(2010 , 2020-05-15, 2020-06 ) = false OK
isDateInRange(2010 , 2020-05-15, 2020-05-16) = false OK
isDateInRange(2010 , 2020-05-15, 2020-06-01) = false OK
isDateInRange(NULL , 2020-05 , 2020-05-31) = true OK
isDateInRange(NULL , 2020-05 , 2020-05 ) = true OK
isDateInRange(NULL , 2020-05 , 2020 ) = true OK
isDateInRange(NULL , 2020-05 , 2020-05-30) = true OK
isDateInRange(NULL , 2020-05 , 2020-04 ) = true OK
isDateInRange(NULL , 2020-05 , 2019 ) = true OK
isDateInRange(NULL , 2020-05 , 2020-06-01) = false OK
isDateInRange(NULL , 2020-05 , 2020-06 ) = false OK
isDateInRange(NULL , 2020-05 , 2021 ) = false OK
isDateInRange(NULL , 2020-05 , 2020-06-02) = false OK
isDateInRange(NULL , 2020-05 , 2020-07 ) = false OK
isDateInRange(NULL , 2020-05 , 2022 ) = false OK
isDateInRange(2010-05-15, NULL , 2010-05-15) = true OK
isDateInRange(2010-05-15, NULL , 2010-05 ) = true OK
isDateInRange(2010-05-15, NULL , 2010 ) = true OK
isDateInRange(2010-05-15, NULL , 2010-05-16) = true OK
isDateInRange(2010-05-15, NULL , 2010-06 ) = true OK
isDateInRange(2010-05-15, NULL , 2011 ) = true OK
isDateInRange(2010-05-15, NULL , 2010-05-14) = false OK
isDateInRange(2010-05-15, NULL , 2010-04 ) = false OK
isDateInRange(2010-05-15, NULL , 2009 ) = false OK
isDateInRange(2010-05-15, NULL , 2010-05-13) = false OK
isDateInRange(2010-05-15, NULL , 2010-03 ) = false OK
isDateInRange(2010-05-15, NULL , 2008 ) = false OK
将所有内容转换为日期范围。将日期范围表示为从开始日期到结束日期不包括 的半开间隔。并将开始日期和结束日期表示为两个 LocalDate
对象。
例如,从您的用例 1
Start date:
2010-05-15
& end date:2020-05
作为日期范围,这变为 从 2010-05-15(含)到 2020-06-01(不含)。
要测试 2010 是否在范围内,请将 2010 转换为 从 2010-01-01 到 2011-01-01 exclusive 的范围。现在,当且仅当这两个范围重叠时,2010 年才在范围内。当且仅当第一个起始日期早于第二个日期 和 第二个起始日期早于第一个日期时,他们才会这样做。使用 LocalDate.isBefore()
。我们需要“strict before”,而这个方法正好给了我们这个。由于 2010-05-15 在 2011-01-01 和 之前 2010-01-01 在 2020-06-01 之前,范围重叠,因此我们得出结论 2010 在范围内.
案例1的另一个例子,为了测试2010-05-14是否在同一范围内,将其转换为范围从2010-05-14到2010-05-15(不包括) 。查看 2010-05-15 是否早于 2010-05-15 和 2010-05-14 是否早于 2020-06-01。前半部分已经是假的,所以我们断定日期不在范围内。
实施说明:我可能会使用此格式化程序来解析您的所有字符串:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu[-MM[-dd]]");
您可以使用此格式化程序的 parseBest
方法从您提到的任何字符串中获取 LocalDate
、YearMonth
或 Year
。在每种情况下,您都可以从那里转换。
Link: Determine Whether Two Date Ranges Overlap
I am not sure if this is a valid solution but this is what I am thinking
Simply break all the dates (requested, start, & end) into numbers and compare requested year with years in start & end, if months in requested date is available and also available in the start and end then compare if the month is in range, and same for the dates.
是的,你的方法是有效的。 java.time 中的 类 没有提供完美的支持,但是使用低级 TemporalAccessor
接口有一个方法:
class IsInRangeWithMissingFields {
@Test
void useCase1() {
assertTrue(isInRange("2010-05-15", "2020-05", "2010"));
assertTrue(isInRange("2010-05-15", "2020-05", "2020"));
assertTrue(isInRange("2010-05-15", "2020-05", "2010-05"));
assertTrue(isInRange("2010-05-15", "2020-05", "2020-05"));
assertTrue(isInRange("2010-05-15", "2020-05", "2020-05-22"));
assertTrue(isInRange("2010-05-15", "2020-05", "2010-05-15"));
assertTrue(isInRange("2010-05-15", "2020-05", "2010-05-22"));
assertTrue(isInRange("2010-05-15", "2020-05", "2015-02-25"));
assertFalse(isInRange("2010-05-15", "2020-05", "2009"));
assertFalse(isInRange("2010-05-15", "2020-05", "2021"));
assertFalse(isInRange("2010-05-15", "2020-05", "2010-04"));
assertFalse(isInRange("2010-05-15", "2020-05", "2020-06"));
assertFalse(isInRange("2010-05-15", "2020-05", "2010-05-14"));
assertFalse(isInRange("2010-05-15", "2020-05", "2020-06-01"));
}
@Test
void useCase2() {
assertTrue(isInRange("2010", "2020-05-15", "2010"));
assertTrue(isInRange("2010", "2020-05-15", "2020"));
assertTrue(isInRange("2010", "2020-05-15", "2010-05"));
assertTrue(isInRange("2010", "2020-05-15", "2020-05"));
assertTrue(isInRange("2010", "2020-05-15", "2010-05-22"));
assertTrue(isInRange("2010", "2020-05-15", "2010-01-01"));
assertTrue(isInRange("2010", "2020-05-15", "2020-05-15"));
assertTrue(isInRange("2010", "2020-05-15", "2015-02-25"));
assertFalse(isInRange("2010", "2020-05-15", "2009"));
assertFalse(isInRange("2010", "2020-05-15", "2021"));
assertFalse(isInRange("2010", "2020-05-15", "2020-06"));
assertFalse(isInRange("2010", "2020-05-15", "2020-05-16"));
assertFalse(isInRange("2010", "2020-05-15", "2020-06-01"));
}
@Test
void useCase3() {
assertTrue(isInRange(null, "2020-05", "2020-05-31"));
assertFalse(isInRange(null, "2020-05", "2020-06-01"));
}
@Test
void useCase4() {
assertTrue(isInRange("2010-05-15", null, "2010-05-15"));
assertFalse(isInRange("2010-05-15", null, "2010-05-14"));
}
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu[-MM[-dd]]");
public static boolean isInRange(String startStr, String endStr, String requestStr) {
TemporalAccessor request = formatter.parse(requestStr);
// is request before start?
if (startStr != null) {
TemporalAccessor start = formatter.parse(startStr);
if (request.get(ChronoField.YEAR)
< start.get(ChronoField.YEAR)) {
return false;
}
if (request.get(ChronoField.YEAR)
== start.get(ChronoField.YEAR)) {
if (request.isSupported(ChronoField.MONTH_OF_YEAR)
&& start.isSupported(ChronoField.MONTH_OF_YEAR)) {
if (request.get(ChronoField.MONTH_OF_YEAR)
< start.get(ChronoField.MONTH_OF_YEAR)) {
return false;
}
if (request.get(ChronoField.MONTH_OF_YEAR)
== start.get(ChronoField.MONTH_OF_YEAR)) {
if (request.isSupported(ChronoField.DAY_OF_MONTH)
&& start.isSupported(ChronoField.DAY_OF_MONTH)) {
if (request.get(ChronoField.DAY_OF_MONTH)
< start.get(ChronoField.DAY_OF_MONTH)) {
return false;
}
}
}
}
}
}
// is request after end?
if (endStr != null) {
TemporalAccessor end = formatter.parse(endStr);
if (request.get(ChronoField.YEAR) > end.get(ChronoField.YEAR)) {
return false;
}
if (request.get(ChronoField.YEAR) == end.get(ChronoField.YEAR)) {
if (request.isSupported(ChronoField.MONTH_OF_YEAR)
&& end.isSupported(ChronoField.MONTH_OF_YEAR)) {
if (request.get(ChronoField.MONTH_OF_YEAR)
> end.get(ChronoField.MONTH_OF_YEAR)) {
return false;
}
if (request.get(ChronoField.MONTH_OF_YEAR)
== end.get(ChronoField.MONTH_OF_YEAR)) {
if (request.isSupported(ChronoField.DAY_OF_MONTH)
&& end.isSupported(ChronoField.DAY_OF_MONTH)) {
if (request.get(ChronoField.DAY_OF_MONTH)
> end.get(ChronoField.DAY_OF_MONTH)) {
return false;
}
}
}
}
}
}
return true;
}
}
此单元测试在我的计算机上运行时出现绿色障碍。