Wednesday, December 29, 2010

An algorithm to find floating holidays

I've always liked dealing with code that works with dates and times. You learn a lot about our calendars and all the hacks to make up for our inaccurate decisions hundreds of years ago and for the earth's wobbles and year-to-year inconsistencies.

One task that's come up again and again is determining floating holidays. Here's a very quick and easy way I discovered to determine floating days (every 4th thursday etc) and fixed days that are observed on friday or monday when the day is a holiday.

All you need is a list or array of the 7 days of the month it falls on. The first element is the day of the month the holiday is on when the month begins on a Sunday, the second element is the day of the month the holiday is on when the month begins on a Monday, and so on. Once you find what day of the week the month starts on, you can just lookup the day you're looking for. So you know the year, the month, and the day the holiday falls on for any year of that calendar.

For example, American Independence day is celebrated on the 4th of July or the closest weekday when it falls on a weekend. Using a calendar we can see that the days of the month are [4,4,4,3,5,4,4], i.e. when July starts on a Wednesday (4th element in the list) the holiday is celebrated on the 3rd, when it starts on a Thursday (5th element in the list) the holiday is celebrated on the 5th, otherwise it's celebrated on the 4th. American Thanksgiving day is celebrated on the 4th Thursday of November so the days of the month are [26,25,24,23,22,21,27], i.e. when November starts on a Sunday the holiday is celebrated on the 26th, when November starts on a Monday the holiday is celebrated on the 25th, etc.

The java is much less verbose than the english description:


public Calendar getAmericanIndependanceDay(int year){
        return getFloatingDay(year, 6, new int[]{4,4,4,3,5,4,4});
    }

    public Calendar getAmericanThanksgivingDay(int year){
        return getFloatingDay(year, 10, new int[]{26,25,24,23,22,21,27});
    }

    private Calendar getFloatingDay(int year, int month, int[] days){
        Calendar firstDayOfTheMonth = new GregorianCalendar(year, month, 1);
        int firstDayOfTheWeek = firstDayOfTheMonth.get(Calendar.DAY_OF_WEEK) - 1;
        return new GregorianCalendar(year, month, days[firstDayOfTheWeek]);
    }

No comments:

Post a Comment