import java.time.DayOfWeek; import java.time.LocalDate; import java.time.Month; import java.time.MonthDay; import java.time.temporal.TemporalAdjusters; import java.util.*; import java.util.function.Function; import java.util.function.Supplier; import java.util.stream.Collectors; import java.util.stream.IntStream; import java.util.stream.Stream; import static java.time.DayOfWeek.*; import static java.time.Month.*; import static java.util.Objects.requireNonNull; /** * Represents the public holidays as declared in Federal law (5 U.S.C. 6103). All dates listed in section (a) are * enumerated. Inauguration day, which is described in section (c) is not enumerated, but is accounted for in the * static {@link #observancesForYear} and {@link #isObserved(LocalDate)} methods. *
* Fixed holidays that fall on specific days each year (e.g. Christmas) are observed on the nearest work day. If the * actual holiday is on a Saturday, the observance occurs on the Friday before; if the holiday is on a Sunday, the * observance occurs on the Monday after. The dates used for such fixed holidays will be the observed dates and not * the actual ones. *
* This method does not account for historical changes in Federal law regarding Holidays and should not be used to
* determine holidays in the past, such as Martin Luther King Jr.'s birthday for years prior to 1983, when the
* observance was formally adopted.
*
* @see
* Federal Holidays - OPM Web site
* @see 5 U.S. Code § 6103 - Holidays
*/
public enum FederalHoliday {
NEW_YEARS("New Year's Day", year -> LocalDate.of(year, JANUARY, 1)),
MLK_JR_BIRTHDAY("Birthday of Martin Luther King, Jr.", year -> nthDayOfWeek(3, MONDAY, JANUARY, year)),
WASHINGTON_BIRTHDAY("Washington's Birthday", year -> nthDayOfWeek(3, MONDAY, FEBRUARY, year)),
MEMORIAL_DAY("Memorial Day", year -> nthDayOfWeek(-1, MONDAY, MAY, year)),
INDEPENDENCE_DAY("Independence Day", year -> LocalDate.of(year, JULY, 4)),
LABOR_DAY("Labor Day", year -> nthDayOfWeek(1, MONDAY, SEPTEMBER, year)),
COLUMBUS_DAY("Columbus Day", year -> nthDayOfWeek(2, MONDAY, OCTOBER, year)),
VETERANS_DAY("Veterans Day", year -> LocalDate.of(year, NOVEMBER, 11)),
THANKSGIVING("Thanksgiving Day", year -> nthDayOfWeek(4, THURSDAY, NOVEMBER, year)),
CHRISTMAS("Christmas Day", year -> LocalDate.of(year, DECEMBER, 25));
private static final MonthDay INAUGURATION_DATE = MonthDay.of(JANUARY, 20);
private final String legalName;
private final Function
* Note: if New Year's Day falls on a Saturday on the year provided, the year of returned date will be December 31st
* of the previous year. This most recently happened in 2011.
*
* @param year the calendar year
* @return the date of this holiday observance for that year
*/
public LocalDate forYear(int year) {
return adjustForWeekends(onDate.apply(year));
}
/**
* Returns the date that falls on the nth day of the week for the given year. For example, the fourth Friday
* in the month of October, 2018 is October 26th, 2018.
*/
private static LocalDate nthDayOfWeek(int n, DayOfWeek dayOfWeek, Month month, int year) {
return LocalDate.of(year, month, 1).with(TemporalAdjusters.dayOfWeekInMonth(n, dayOfWeek));
}
/**
* Adjusts the date, if necessary, so that it does not fall on a weekend. If the date is on a Saturday, returns
* the previous Friday; if it's on a Sunday, returns the following Monday.
*/
private static LocalDate adjustForWeekends(LocalDate date) {
switch (date.getDayOfWeek()) {
case SATURDAY:
return date.minusDays(1);
case SUNDAY:
return date.plusDays(1);
default:
return date;
}
}
/**
* For the purposes of this class it is assumed 1965 itself is an inauguration year.
*/
private static boolean isInaugurationYear(int year) {
return (year - 1965) % 4 == 0;
}
/**
* According to Federal law (5 U.S.C. 6103):
*
* "January 20 of each fourth year after 1965, Inauguration Day, is a legal public holiday for the purpose of
* statutes relating to pay and leave of employees...employed by the government of the District of Columbia employed
* in the District of Columbia, Montgomery and Prince Georges Counties in Maryland, Arlington and Fairfax Counties
* in Virginia, and the cities of Alexandria and Falls Church in Virginia. When January 20 of any fourth year after
* 1965 falls on Sunday, the next succeeding day selected for the public observance of the inauguration of the
* President is a legal public holiday for the purpose of this subsection."
*
* If the given year is an inauguration year, January 20th of that year (adjusted for weekends) will be returned.
* Otherwise, the returned optional will be empty
*
* @param year some calendar year, e.g. 2018
* @return an empty optional if the given year did not have an inauguration day
*/
public static Optional
* If the year happens to be the year of an inauguration, then the list will also include the date of the
* inauguration, provided the observed inauguration date that year does not coincide with Martin Luther King Jr.'s
* Birthday, as it did in 2013.
*
* @param year some calendar year, e.g. 2018
* @return a chronologically ordered set of the observed Federal Holidays that fall within that year.
*/
public static SortedSet
* Generally, this method should not be used for determining historic non-workdays. The rules currently implemented
* within this class have not always been in effect (e.g. Columbus Day was not a holiday until 1968). Furthermore,
* this method does not take into account days where Federal offices closed due to weather or shutdown reasons.
*
* Caution should also be used when using this method for dates in the far future as laws or circumstances may
* change between now and that date, causing the rules currently implemented to be inapplicable at that time.
*
* @param date cannot be null
* @return true when the date is a weekend or observed Federal holiday, inauguration days included
*/
public static boolean isNonWorkday(LocalDate date) {
requireNonNull(date);
return isWeekend(date) || isObserved(date);
}
}