我有“ LocalDate”类型的结婚日期列表,我想找到在接下来的30天内有周年纪念日的人的列表。所有的结婚日期都来自过去的年份,例如1980、1990、2000 ...
我尝试使用ChronoUnit.DAYS.between()函数,但是如果日期是今天和将来的日期,它只会显示天数。
String str = "2019-04-24";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(str, formatter);
LocalDate today = LocalDate.now();
long dd = ChronoUnit.DAYS.between(today, date);
我希望得到的答案是,如果结婚日期是1990-04-29,那么它应该告诉我该结婚日期是否在接下来的30天内。意思是,上述日期的周年纪念日是否在接下来的30天内。
答案 0 :(得分:3)
此计算所需的测试用例为:
Today Marriage Days between
2000-01-01 ????-01-01 0
2000-01-01 ????-01-02 1
2000-01-01 ????-01-31 30
2000-01-01 ????-12-31 365 since 2000 is a leap year
2001-01-01 ????-12-31 364 since 2001 is not a leap year
2000-02-28 ????-03-01 2 since 2000 is a leap year
2000-12-31 ????-01-01 1
2000-12-01 ????-11-30 364 since 2001 is not a leap year
1999-12-01 ????-11-30 365 since 2000 is not a leap year
这些测试用例提示了如何做。
第4步将处理of年。
我建议编写这种方法:
int daysUntilNextAnniversary(LocalDate today, LocalDate anniversary) {
...
}
anniversary 一词已经包含了与周年纪念日无关的信息,与上面的测试案例相符。
然后您可以像这样轻松地使用它:
int days = daysUntilNextAnniversary(LocalDate.now(), marriage);
if (1 <= days && days <= 30) {
...
}
以下是上述测试用例的测试代码:
package de.roland_illig.so;
import static org.junit.Assert.assertEquals;
import java.time.LocalDate;
import org.junit.Test;
public class AnnivTest {
// Interesting test cases are:
//
// Marriage:
// - Jan 01 in leap year
// - Feb 29 in leap year
// - Dec 31 in leap year
// - Jan 01 in year after leap year
//
// Today:
// - Jan 01 in leap year
// - Feb 28 in leap year
// - Feb 28 in year before leap year
// - Feb 29 in leap year
// - Dec 31 in leap year
// - Dec 31 in year before leap year
//
// Ideally the test would test every combination of marriage and today.
@Test
public void daysUntilNextAnniversary() {
test("2000-01-01", "01-01", 0);
test("2000-01-01", "01-02", 1);
test("2000-01-01", "01-31", 30);
test("2000-01-01", "12-31", 365); // since 2000 is a leap year
test("2001-01-01", "12-31", 364); // since 2001 is not a leap year
test("2000-02-28", "03-01", 2); // since 2000 is a leap year
test("2000-12-31", "01-01", 1);
test("2000-12-01", "11-30", 364); // since 2001 is not a leap year
test("1999-12-01", "11-30", 365); // since 2000 is not a leap year
// Ensures that the marriage is not moved to Feb 28 just
// because the current year doesn't have Feb 29. This happens
// when an intermediate result is 2019-02-29, which is corrected
// to 2019-02-28.
test("2019-12-31", "02-29", 60);
// In a non-leap-year, Feb 28 and Feb 29 are merged into one day.
test("2019-02-28", "02-29", 0);
}
private void test(String today, String marriage, int expectedDays) {
int actual = Anniv.daysUntilNextAnniversary(
LocalDate.parse(today),
LocalDate.parse("1996-" + marriage));
assertEquals(expectedDays, actual);
}
}
这是计算的实际代码:
package de.roland_illig.so;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class Anniv {
public static int daysUntilNextAnniversary(LocalDate today, LocalDate anniversary) {
LocalDate d = anniversary.withYear(today.getYear());
if (d.isBefore(today)) {
d = anniversary.withYear(today.getYear() + 1);
}
return Math.toIntExact(ChronoUnit.DAYS.between(today, d));
}
}
如您所见,测试代码比实际的应用程序代码长得多。在处理日期计算时,这是必需的。当不同时区发挥作用时,甚至更多。 leap秒。和其他日历异常。
答案 1 :(得分:1)
因此,“基本”概念是,您希望获取日期列表并更改年份以匹配今年。 “捕获”是指,如果结果日期在今天之前,则应将年份加1,这样,如果现在是12月,则将捕获在1月发生的所有周年纪念日。
也许像...
one = ['Here is a striiing']
two = ['Here is another string']
asdf = list(d.compare(one, two))
for item in asdf:
print(item)
> - Here is a striiing
> ? --
>
> + Here is another string
> ? ++++++
然后,您只需检查日期是否在所需范围内...
LocalDate now = LocalDate.now();
int year = now.getYear();
List<LocalDate> dates = ...;
List<LocalDate> adjusted = new ArrayList<>(10);
for (LocalDate date : dates) {
LocalDate warped = date.withYear(year);
if (warped.isBefore(now)) {
warped = warped.withYear(year + 1);
}
adjusted.add(warped);
}
因此,使用相同的伪随机生成的日期,我可以获得类似...的结果
LocalDate limit = now.plusDays(30);
for (LocalDate date : adjusted) {
if ((date.isAfter(now) || date.isEqual(now)) && (date.isBefore(limit) || date.isEqual(limit))) {
System.out.println("~~ " + date);
}
}
如果我们将锚定日期更改为Input date 2019-04-19
+---------------+---------------+--------------+
| Original Date | Adjusted Date | Within range |
+---------------+---------------+--------------+
| 1996-04-13 | 2020-04-13 | |
| 1986-04-24 | 2019-04-24 | X |
| 1989-04-23 | 2019-04-23 | X |
| 1960-05-11 | 2019-05-11 | X |
| 1986-05-18 | 2019-05-18 | X |
| 1984-04-06 | 2020-04-06 | |
| 1997-05-29 | 2019-05-29 | |
| 2008-03-31 | 2020-03-31 | |
| 2014-04-18 | 2020-04-18 | |
| 1982-04-23 | 2019-04-23 | X |
+---------------+---------------+--------------+
之类的内容,则可能会生成类似...的内容。
2019-12-20
因此它正在捕获明年的日期。
nb:我会随机生成测试日期,该日期应在锚定日期的+/-一个月内,以便获得更好的测试数据。
答案 2 :(得分:0)
由于您根本不关心年份:
private static boolean isWithinNext30Days(LocalDate date, LocalDate today) {
int todayYear = today.getYear();
int todayMonth = today.getMonthValue();
int dateMonth = date.getMonthValue();
if (todayMonth > dateMonth) {
date = date.withYear(todayYear + 1);
return today.plusDays(30).isAfter(date) && date.isAfter(today);
}
LocalDate alteredDate = date.withYear(todayYear);
return today.plusDays(30).isAfter(alteredDate) && alteredDate.isAfter(today);
}
答案 3 :(得分:-1)
尝试计算今年的周年纪念日,找出现在和那个日期之间的差额:
String str = "2008-05-20";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
LocalDate date = LocalDate.parse(str, formatter);
LocalDate today = LocalDate.now();
long dd = ChronoUnit.DAYS.between(today, date);
System.err.println("YOUR ANSWER WAS " + dd);
LocalDate thisYearsAnniversary = LocalDate.of(today.getYear(), date.getMonth(), date.getDayOfMonth());
System.err.println("THIS YEARS ANNIVERSARY IS " + thisYearsAnniversary);
dd = ChronoUnit.DAYS.between(today, thisYearsAnniversary);
System.err.println("WHICH IS IN " + dd + " days");
输出
YOUR ANSWER WAS -3981
THIS YEARS ANNIVERSARY IS 2019-05-24
WHICH IS IN 36 days