Необходимые тестовые примеры для этого расчета:
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 будет заботиться о високосных годах.
Предлагаю написать этот метод:
int daysUntilNextAnniversary(LocalDate today, LocalDate 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));
}
}
Как видите, тестовый код намного длиннее, чем реальный код приложения. При работе с датами вычислений это необходимо. Еще больше, когда в игру вступают разные часовые пояса. И високосные секунды. И другие календарные аномалии.