Search code examples
javaunit-testingjunitgregorian-calendarjava.util.calendar

How to set a recurring holiday on the same date every year (disregarding the year component) with java using java.util.Calendar?


I am making a calendar that allows you to add a specific holiday which recurs each year automatically. My WorkdayCalendar.class needs 2 methods: -setHoliday(Calendar date) which sets a holiday only within that year -setRecurringHoliday(Calendar date) which should (preferably) use setHoliday() and set it recurring each year. How do I implement the logic that checks if it is a new year? I am adding holidays to a HashSet named holidaysList. I need a method that checks if it is a new year and then adds a specified holiday. The setHoliday works fine and has been tested wih unitTests.

public void setHoliday(Calendar date) {
    this.date = date.getTime();
    if (!isHoliday(date)) {
        holidaysList.add(this.date);
    }
}

public void setRecurringHoliday(Calendar date) {
    SimpleDateFormat sdf = new SimpleDateFormat("dd-MM-yyyy HH:mm");
    GregorianCalendar todaysDate = new GregorianCalendar();

    System.out.println(
            sdf.format("Todays date: " + todaysDate.getTime()) + "\n");

    int thisYear = todaysDate.get(Calendar.YEAR);
    int chosenYear = date.get(Calendar.YEAR);
    System.out.println("Chosen year: " + chosenYear + "\nThis year: " + thisYear);

    date.add(Calendar.YEAR, 1);
    int nextYear = date.get(Calendar.YEAR);
    System.out.println("Next year: " + nextYear);


    /*What to do here???*/
    if (thisYear == nextYear){
        setHoliday(date);
        System.out.println("recurring holiday added");
    }

}

private boolean isHoliday(Calendar date) {
    this.date = date.getTime();
    return isWeekend(date) || holidaysList.contains(this.date);
}

private boolean isWeekend(Calendar date) {
     int chosenDay = date.get(Calendar.DAY_OF_WEEK);
    return chosenDay == Calendar.SATURDAY || chosenDay == Calendar.SUNDAY;
}

Solution

  • You are using terrible date-time classes that were years ago supplanted by the java.time classes defined in JSR 310.

    MonthDay

    For a month and day-of-month without year, use MonthDay.

    MonthDay xmas = MonthDay.of( Month.DECEMBER , 25 ) ;
    

    Your set of holidays should be a set MonthDay objects, from what I can discern of your Question. I find your overall Question confusing as its logic falls short of what you need for the usual workplace holiday tracking.

    Set< MonthDay > holidays = new TreeSet<>() ;
    holidays.add( xmas ) ;
    

    For a date, use LocalDate.

    Apply a year to get a date.

    LocalDate xmas2020 = xmas.atYear( 2020 ) ;
    

    To get current year, use Year, and specify a time zone. For any given moment, the date, and therefore possibly the year, varies around the globe by zone.

    ZoneId z = ZoneId.of( "Africa/Tunis" ) ;
    Year currentYear = Year.now( z ) ;
    LocalDate xmasThisYear = currentYear.atMonthDay( xmas ) ;
    

    Add to Year for next year.

    Year nextYear = currentYear.plusYears( 1 ) ;
    LocalDate xmasNextYear = nextYear.atMonthDay( xmas ) ;
    

    Ask if a date is this year or next.

    boolean isThisYear = Year.from( localDate ).equals( currentYear ) ;
    boolean isNextYear = Year.from( localDate ).equals( nextYear ) ;
    boolean isFutureYear = Year.from( localDate ).isAfter( currentYear ) ;
    

    For your check of the weekend, define an EnumSet of the desired day of week values as defined in the DayOfWeek enum.

    Set< DayOfWeek > weekend = EnumSet.of( DayOfWeek.SATURDAY , DayOfWeek.SUNDAY ) ;
    boolean isWeekend = weekend.contains( localDate.getDayOfWeek() ) ;