diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/Holiday.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/Holiday.java index 6a744e607..84b7afb1d 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/Holiday.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/Holiday.java @@ -4,6 +4,8 @@ import java.time.LocalDate; import java.util.Locale; +import java.util.Objects; +import java.util.Optional; /** * Represents the holiday and contains the actual date and an localized @@ -14,15 +16,19 @@ public final class Holiday implements Comparable { * The calculated hashcode cached for performance. */ private int hashCode = 0; + /** * The date the holiday occurs. */ - private final LocalDate date; + private final LocalDate actualDate; + /** + * The observed date of the holiday. + */ + private final LocalDate observedDate; /** * The properties key to retrieve the description with. */ private final String propertiesKey; - /** * The type of holiday. e.g. official holiday or not. */ @@ -32,26 +38,68 @@ public final class Holiday implements Comparable { * Constructs a holiday for a date using the provided properties key to * retrieve the description with. * - * @param date a {@link LocalDate} object. + * @param actualDate a {@link LocalDate} object. + * @param propertiesKey a {@link java.lang.String} object. + * @param type a {@link HolidayType} object. + */ + public Holiday(final LocalDate actualDate, final String propertiesKey, final HolidayType type) { + this(actualDate, null, propertiesKey, type); + } + + /** + * Constructs a holiday for a date using the provided properties key to + * retrieve the description with. + * + * @param actualDate a {@link LocalDate} object. + * @param observedDate a {@link LocalDate} object. * @param propertiesKey a {@link java.lang.String} object. * @param type a {@link HolidayType} object. */ - public Holiday(final LocalDate date, final String propertiesKey, final HolidayType type) { + public Holiday(final LocalDate actualDate, final LocalDate observedDate, final String propertiesKey, final HolidayType type) { super(); this.type = type; - this.date = date; + this.actualDate = actualDate; + this.observedDate = observedDate; this.propertiesKey = propertiesKey == null ? "" : propertiesKey; } /** + * Returns the calculated holiday date. + *

+ * If the holiday is {@link de.focus_shift.jollyday.core.spi.Movable} and the holiday was moved, then: + *

*

- * Getter for the field date. + * @return if holiday was moved the observed date, otherwise the actual date + */ + public LocalDate getDate() { + return Optional.ofNullable(observedDate).orElse(actualDate); + } + + /** + *

+ * Returns the actual date. + *

+ * If you want the observed holiday date then use {@link #getObservedDate()} *

* - * @return the holiday date + * @return the actual holiday date */ - public LocalDate getDate() { - return date; + public LocalDate getActualDate() { + return actualDate; + } + + /** + *

+ * Getter for the field observedDate. + *

+ * + * @return the observed holiday date + */ + public LocalDate getObservedDate() { + return observedDate; } /** @@ -86,31 +134,27 @@ public String getDescription(Locale locale) { @Override public boolean equals(final Object obj) { - if (obj == this) { - return true; - } - if (obj instanceof Holiday) { - final Holiday other = (Holiday) obj; - return other.date.equals(this.date) && other.propertiesKey.equals(this.propertiesKey) && type.equals(other.type); + if (obj == null || getClass() != obj.getClass()) { + return false; } - return false; + + final Holiday holiday = (Holiday) obj; + return Objects.equals(getDate(), holiday.getDate()) && + Objects.equals(propertiesKey, holiday.propertiesKey) && + type == holiday.type; } @Override public int hashCode() { if (hashCode == 0) { - int hash = 1; - hash = hash * 31 + date.hashCode(); - hash = hash * 31 + propertiesKey.hashCode(); - hash = hash * 31 + type.hashCode(); - hashCode = hash; + hashCode = Objects.hash(getDate(), propertiesKey, type); } return hashCode; } @Override public String toString() { - return date.toString() + " (" + getDescription() + ")"; + return actualDate.toString() + " (" + getDescription() + ")"; } /** diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/functions/CreateHoliday.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/functions/CreateHoliday.java index 1c085ff67..4509e9ad5 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/functions/CreateHoliday.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/functions/CreateHoliday.java @@ -8,14 +8,20 @@ public class CreateHoliday implements Function { - private final LocalDate localDate; + private final LocalDate actualDate; + private final LocalDate observedDate; - public CreateHoliday(LocalDate localDate) { - this.localDate = localDate; + public CreateHoliday(final LocalDate actualDate) { + this(actualDate, null); + } + + public CreateHoliday(final LocalDate actualDate, final LocalDate observedDate) { + this.actualDate = actualDate; + this.observedDate = observedDate; } @Override public Holiday apply(final Described described) { - return new Holiday(localDate, described.descriptionPropertiesKey(), described.holidayType()); + return new Holiday(actualDate, observedDate, described.descriptionPropertiesKey(), described.holidayType()); } } diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/ChristianHolidayParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/ChristianHolidayParser.java index 9531dcd0d..fe14ca716 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/ChristianHolidayParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/ChristianHolidayParser.java @@ -24,9 +24,11 @@ public class ChristianHolidayParser implements HolidayParser { public List parse(final Year year, final Holidays holidays) { return holidays.christianHolidays().stream() .filter(new ValidLimitation(year)) - .map(ch -> { - LocalDate easterSunday = new CalculateEasterSunday(year).apply(ch.chronology()); - switch (ch.type()) { + .map(christianHoliday -> { + + LocalDate easterSunday = new CalculateEasterSunday(year).apply(christianHoliday.chronology()); + + switch (christianHoliday.type()) { case EASTER: break; case CLEAN_MONDAY: @@ -76,10 +78,10 @@ public List parse(final Year year, final Holidays holidays) { easterSunday = easterSunday.plusDays(68); break; default: - throw new IllegalArgumentException("Unknown christian holiday type " + ch.type()); + throw new IllegalArgumentException("Unknown christian holiday type " + christianHoliday.type()); } - easterSunday = new MoveDateRelative(easterSunday).apply(ch); - return new CreateHoliday(easterSunday).apply(ch); + final LocalDate movedChristianHoliday = new MoveDateRelative(easterSunday).apply(christianHoliday); + return new CreateHoliday(easterSunday, movedChristianHoliday).apply(christianHoliday); }) .collect(toList()); } diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/DescribedDateHolder.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/DescribedDateHolder.java index 91d9ee1e7..8690625c8 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/DescribedDateHolder.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/DescribedDateHolder.java @@ -6,16 +6,26 @@ class DescribedDateHolder { - private final LocalDate date; + private final LocalDate actualDate; + private final LocalDate observedDate; private final Described described; - public DescribedDateHolder(final Described described, final LocalDate date) { - this.date = date; + DescribedDateHolder(final Described described, final LocalDate actualDate) { + this(described, actualDate, null); + } + + DescribedDateHolder(final Described described, final LocalDate actualDate, final LocalDate observedDate) { + this.actualDate = actualDate; + this.observedDate = observedDate; this.described = described; } - public LocalDate getDate() { - return date; + public LocalDate getActualDate() { + return actualDate; + } + + public LocalDate getObservedDate() { + return observedDate; } public Described getDescribed() { diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedParser.java index 7f7dd6057..eaadf4618 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedParser.java @@ -22,8 +22,8 @@ public class FixedParser implements HolidayParser { public List parse(final Year year, final Holidays holidays) { return holidays.fixed().stream() .filter(new ValidLimitation(year)) - .map(fixed -> new DescribedDateHolder(fixed, new MoveDateRelative(new FixedToLocalDate(year).apply(fixed)).apply(fixed))) - .map(describedDateHolder -> new CreateHoliday(describedDateHolder.getDate()).apply(describedDateHolder.getDescribed())) + .map(fixed -> new DescribedDateHolder(fixed, new FixedToLocalDate(year).apply(fixed), new MoveDateRelative(new FixedToLocalDate(year).apply(fixed)).apply(fixed))) + .map(describedDateHolder -> new CreateHoliday(describedDateHolder.getActualDate(), describedDateHolder.getObservedDate()).apply(describedDateHolder.getDescribed())) .collect(toList()); } } diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayBetweenFixedParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayBetweenFixedParser.java index a4c27590b..62f41a16c 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayBetweenFixedParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayBetweenFixedParser.java @@ -29,7 +29,7 @@ public List parse(final Year year, final Holidays holidays) { ).apply(fwm) ) ) - .map(holder -> new CreateHoliday(holder.getDate()).apply(holder.getDescribed())) + .map(holder -> new CreateHoliday(holder.getActualDate()).apply(holder.getDescribed())) .collect(toList()); } } diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayInMonthParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayInMonthParser.java index dde60bd1f..6c779def1 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayInMonthParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayInMonthParser.java @@ -22,7 +22,7 @@ public List parse(final Year year, final Holidays holidays) { return holidays.fixedWeekdays().stream() .filter(new ValidLimitation(year)) .map(fwm -> new DescribedDateHolder(fwm, new FindWeekDayInMonth(year).apply(fwm))) - .map(holder -> new CreateHoliday(holder.getDate()).apply(holder.getDescribed())) + .map(holder -> new CreateHoliday(holder.getActualDate()).apply(holder.getDescribed())) .collect(toList()); } } diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayRelativeToFixedParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayRelativeToFixedParser.java index d8900d211..8b2e5c78d 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayRelativeToFixedParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/FixedWeekdayRelativeToFixedParser.java @@ -28,7 +28,7 @@ public List parse(final Year year, final Holidays holidays) { new FindWeekDayRelativeToDate(new FixedToLocalDate(year).apply(weekdayRelativeToFixed.day())).apply(weekdayRelativeToFixed) ) ) - .map(holder -> new CreateHoliday(holder.getDate()).apply(holder.getDescribed())) + .map(holder -> new CreateHoliday(holder.getActualDate()).apply(holder.getDescribed())) .collect(toList()); } } diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java index ea0ce6e93..2504de994 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParser.java @@ -80,8 +80,8 @@ public List parse(final Year year, final Holidays holidays) { } return islamicHolidays - .map(date -> new MoveDateRelative(date).apply(islamicHoliday)) - .map(date -> new CreateHoliday(date).apply(islamicHoliday)); + .map(date -> new DescribedDateHolder(islamicHoliday, date, new MoveDateRelative(date).apply(islamicHoliday))) + .map(describedDateHolder -> new CreateHoliday(describedDateHolder.getActualDate(), describedDateHolder.getObservedDate()).apply(islamicHoliday)); }) .collect(toList()); diff --git a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/RelativeToEasterSundayParser.java b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/RelativeToEasterSundayParser.java index f8af31d2c..b597a3ace 100644 --- a/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/RelativeToEasterSundayParser.java +++ b/jollyday-core/src/main/java/de/focus_shift/jollyday/core/parser/impl/RelativeToEasterSundayParser.java @@ -22,7 +22,7 @@ public List parse(final Year year, final Holidays holidays) { return holidays.relativeToEasterSunday().stream() .filter(new ValidLimitation(year)) .map(res -> new DescribedDateHolder(res, new CalculateEasterSunday(year).apply(res.chronology()).plus(res.days()))) - .map(holder -> new CreateHoliday(holder.getDate()).apply(holder.getDescribed())) + .map(holder -> new CreateHoliday(holder.getActualDate()).apply(holder.getDescribed())) .collect(toList()); } } diff --git a/jollyday-core/src/test/java/de/focus_shift/jollyday/core/HolidayTest.java b/jollyday-core/src/test/java/de/focus_shift/jollyday/core/HolidayTest.java index 69240005f..7aad3b099 100644 --- a/jollyday-core/src/test/java/de/focus_shift/jollyday/core/HolidayTest.java +++ b/jollyday-core/src/test/java/de/focus_shift/jollyday/core/HolidayTest.java @@ -50,6 +50,20 @@ void testHolidayDescription() { assertThat(holiday.getDescription(new Locale("nl"))).isEqualTo("Kerstmis"); } + @Test + void ensureToReturnObservedDateIfPresent() { + final LocalDate observedDate = LocalDate.of(2011, 2, 10); + final Holiday holiday = new Holiday(LocalDate.of(2011, 2, 2), observedDate, "CHRISTMAS", PUBLIC_HOLIDAY); + assertThat(holiday.getDate()).isEqualTo(observedDate); + } + + @Test + void ensureToReturnActualDateIfObservedDateIsNotPresent() { + final LocalDate date = LocalDate.of(2011, 2, 2); + final Holiday holiday = new Holiday(date, "CHRISTMAS", PUBLIC_HOLIDAY); + assertThat(holiday.getDate()).isEqualTo(date); + } + @Test void testHolidayEquals() { final Holiday h1 = new Holiday(LocalDate.of(2011, 2, 2), "CHRISTMAS", PUBLIC_HOLIDAY); diff --git a/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java b/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java index 6508d6c57..28ea92246 100644 --- a/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java +++ b/jollyday-core/src/test/java/de/focus_shift/jollyday/core/parser/impl/IslamicHolidayParserTest.java @@ -54,5 +54,7 @@ public DayOfWeek weekday() { // ID_UL_ADHA_2 will be on a sunday in 2022 final List calculatedHoliday = sut.parse(Year.of(2022), holidays); assertThat(calculatedHoliday.get(0).getDate().getDayOfWeek()).isEqualTo(DayOfWeek.MONDAY); + assertThat(calculatedHoliday.get(0).getActualDate().getDayOfWeek()).isEqualTo(DayOfWeek.SUNDAY); + assertThat(calculatedHoliday.get(0).getObservedDate().getDayOfWeek()).isEqualTo(DayOfWeek.MONDAY); } }