Skip to content

Commit

Permalink
Provide actual and observed holiday date
Browse files Browse the repository at this point in the history
  • Loading branch information
derTobsch committed Jan 3, 2025
1 parent 08832f4 commit 73e73c6
Show file tree
Hide file tree
Showing 15 changed files with 174 additions and 84 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -14,15 +16,19 @@ public final class Holiday implements Comparable<Holiday> {
* 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.
*/
Expand All @@ -32,26 +38,67 @@ public final class Holiday implements Comparable<Holiday> {
* 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 date, final String propertiesKey, final HolidayType type) {
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 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.
* <p>
* If the holiday is {@link de.focus_shift.jollyday.core.spi.Movable} and the holiday was moved, then:
* <ul>
* <li>the observed holiday date is given</li>
* <li>otherwise, the actual holiday date</li>
* </ul>
* @return if holiday was moved the observed date, otherwise the actual date
*/
public LocalDate getDate() {
return Optional.ofNullable(observedDate).orElse(actualDate);
}

/**
* <p>
* Getter for the field <code>date</code>.
* Returns the actual date.
* <p>
* If you want the observed holiday date then use {@link #getObservedDate()}
* </p>
*
* @return the holiday date
* @return the actual holiday date
*/
public LocalDate getDate() {
return date;
public LocalDate getActualDate() {
return actualDate;
}

/**
* <p>
* Getter for the field <code>observedDate</code>.
* </p>
*
* @return the observed holiday date as optional
*/
public Optional<LocalDate> getObservedDate() {
return Optional.ofNullable(observedDate);
}

/**
Expand Down Expand Up @@ -86,31 +133,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 getDate().toString() + " (" + getDescription() + ")";
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@

public class CreateHoliday implements Function<Described, Holiday> {

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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@
import de.focus_shift.jollyday.core.spi.Movable;

import java.time.LocalDate;
import java.util.Optional;
import java.util.function.Function;

import static de.focus_shift.jollyday.core.spi.Movable.MovingCondition.With.NEXT;
import static java.time.temporal.TemporalAdjusters.nextOrSame;
import static java.time.temporal.TemporalAdjusters.previousOrSame;

public class MoveDateRelative implements Function<Movable, LocalDate> {
public class MoveDateRelative implements Function<Movable, Optional<LocalDate>> {

private final LocalDate date;

Expand All @@ -19,10 +20,10 @@ public MoveDateRelative(final LocalDate date) {
}

@Override
public LocalDate apply(final Movable movable) {
public Optional<LocalDate> apply(final Movable movable) {
return movable.conditions().stream()
.filter(new ValidMovingCondition(date))
.map(condition -> date.with(condition.with() == NEXT ? nextOrSame(condition.weekday()) : previousOrSame(condition.weekday())))
.findFirst().orElse(date);
.findFirst();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,62 +24,70 @@ public class ChristianHolidayParser implements HolidayParser {
public List<Holiday> 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(christianHolidayConfiguration -> {

final LocalDate easterSunday = new CalculateEasterSunday(year).apply(christianHolidayConfiguration.chronology());

final LocalDate actualDate;
switch (christianHolidayConfiguration.type()) {
case EASTER:
actualDate = easterSunday;
break;
case CLEAN_MONDAY:
case SHROVE_MONDAY:
easterSunday = easterSunday.minusDays(48);
actualDate = easterSunday.minusDays(48);
break;
case MARDI_GRAS:
case CARNIVAL:
easterSunday = easterSunday.minusDays(47);
actualDate = easterSunday.minusDays(47);
break;
case ASH_WEDNESDAY:
easterSunday = easterSunday.minusDays(46);
actualDate = easterSunday.minusDays(46);
break;
case MAUNDY_THURSDAY:
easterSunday = easterSunday.minusDays(3);
actualDate = easterSunday.minusDays(3);
break;
case GOOD_FRIDAY:
easterSunday = easterSunday.minusDays(2);
actualDate = easterSunday.minusDays(2);
break;
case EASTER_SATURDAY:
easterSunday = easterSunday.minusDays(1);
actualDate = easterSunday.minusDays(1);
break;
case EASTER_MONDAY:
easterSunday = easterSunday.plusDays(1);
actualDate = easterSunday.plusDays(1);
break;
case EASTER_TUESDAY:
easterSunday = easterSunday.plusDays(2);
actualDate = easterSunday.plusDays(2);
break;
case GENERAL_PRAYER_DAY:
easterSunday = easterSunday.plusDays(26);
actualDate = easterSunday.plusDays(26);
break;
case ASCENSION_DAY:
easterSunday = easterSunday.plusDays(39);
actualDate = easterSunday.plusDays(39);
break;
case PENTECOST:
case WHIT_SUNDAY:
easterSunday = easterSunday.plusDays(49);
actualDate = easterSunday.plusDays(49);
break;
case WHIT_MONDAY:
case PENTECOST_MONDAY:
easterSunday = easterSunday.plusDays(50);
actualDate = easterSunday.plusDays(50);
break;
case CORPUS_CHRISTI:
easterSunday = easterSunday.plusDays(60);
actualDate = easterSunday.plusDays(60);
break;
case SACRED_HEART:
easterSunday = easterSunday.plusDays(68);
actualDate = easterSunday.plusDays(68);
break;
default:
throw new IllegalArgumentException("Unknown christian holiday type " + ch.type());
throw new IllegalArgumentException("Unknown christian holiday type " + christianHolidayConfiguration.type());
}
easterSunday = new MoveDateRelative(easterSunday).apply(ch);
return new CreateHoliday(easterSunday).apply(ch);

return new MoveDateRelative(actualDate).apply(christianHolidayConfiguration)
.map(observedDate -> new CreateHoliday(actualDate, observedDate))
.orElseGet(() -> new CreateHoliday(actualDate))
.apply(christianHolidayConfiguration);

})
.collect(toList());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import de.focus_shift.jollyday.core.parser.predicates.ValidLimitation;
import de.focus_shift.jollyday.core.spi.Holidays;

import java.time.LocalDate;
import java.time.Year;
import java.util.List;

Expand All @@ -22,8 +23,12 @@ public class FixedParser implements HolidayParser {
public List<Holiday> 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(fixedConfiguration -> {
final LocalDate actualDate = new FixedToLocalDate(year).apply(fixedConfiguration);
final LocalDate observedDate = new MoveDateRelative(actualDate).apply(fixedConfiguration).orElse(null);
return new DescribedDateHolder(fixedConfiguration, actualDate, observedDate);
})
.map(describedDateHolder -> new CreateHoliday(describedDateHolder.getActualDate(), describedDateHolder.getObservedDate()).apply(describedDateHolder.getDescribed()))
.collect(toList());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public List<Holiday> 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public List<Holiday> 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());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public List<Holiday> 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());
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ public List<Holiday> 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).orElse(null)))
.map(describedDateHolder -> new CreateHoliday(describedDateHolder.getActualDate(), describedDateHolder.getObservedDate()).apply(islamicHoliday));

})
.collect(toList());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ public List<Holiday> 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());
}
}
Loading

0 comments on commit 73e73c6

Please sign in to comment.