it-swarm.com.de

Eine gute Business-Kalender-Bibliothek in Java?

Kennt jemand eine gute Geschäftskalender Bibliothek in Java?

Es sollte einfach zu handhaben sein :) Datumsberechnungen unter Berücksichtigung von Feiertagen.

Im Idealfall sollten wir nicht nur Feiertage konfigurieren und arbeitsfreie Tage konfigurieren können, sondern auch Arbeitszeiten konfigurieren 'auf Tagesbasis, damit wir SLAs und KPIs für die Arbeitszeiten berechnen können.

Ich weiß, dass so etwas Teil von jboss jBpm ist, aber ich habe mich gefragt, ob es ein anderes Projekt gibt, das dies tut.

Natürlich ist Open Source ein großer Pluspunkt!

33
HeDinges

Schauen Sie sich diese Bibliothek an, sie hat Funktionalität für Feiertage und so ist sie um Joda herum gebaut.

http://objectlabkit.sourceforge.net/

18
eli

Nachfolgend finden Sie eine sehr lange Antwort. Es ist etwas, das ich zu genau diesem Zweck zusammengestellt habe. Es ist nicht sehr benutzerfreundlich, aber es sollte Ihnen helfen, dass Sie suchen.

Es beruht auf dem Projekt Apache Commons, das hier erworben werden kann: http://commons.Apache.org/lang/

package com.yourPackageName;

import Java.util.ArrayList;
import Java.util.Calendar;
import Java.util.Date;
import Java.util.GregorianCalendar;
import Java.util.HashMap;
import Java.util.List;
import Java.util.Map;

import org.Apache.commons.lang.time.DateUtils;
import org.Apache.commons.logging.Log;
import org.Apache.commons.logging.LogFactory;

public class BusinessDayUtil {
    private static Log log = LogFactory.getLog(BusinessDayUtil.class);
    private static transient Map<Integer, List<Date>> computedDates = new HashMap<Integer, List<Date>>();

    /*
     * This method will calculate the next business day 
     * after the one input.  This means that if the next 
     * day falls on a weekend or one of the following 
     * holidays then it will try the next day. 
     * 
     * Holidays Accounted For: 
     * New Year's Day
     * Martin Luther King Jr. Day
     * President's Day 
     * Memorial Day 
     * Independence Day
     * Labor Day 
     * Columbus Day 
     * Veterans Day
     * Thanksgiving Day 
     * Christmas Day
     *  
     */
    public static boolean isBusinessDay(Date dateToCheck)
    {
        //Setup the calendar to have the start date truncated 
        Calendar baseCal = Calendar.getInstance();
        baseCal.setTime(DateUtils.truncate(dateToCheck, Calendar.DATE));

        List<Date> offlimitDates;

        //Grab the list of dates for the year.  These SHOULD NOT be modified. 
        synchronized (computedDates)
        {
            int year = baseCal.get(Calendar.YEAR);

            //If the map doesn't already have the dates computed, create them.
            if (!computedDates.containsKey(year))
                computedDates.put(year, getOfflimitDates(year));
            offlimitDates = computedDates.get(year);
        }

        //Determine if the date is on a weekend. 
        int dayOfWeek = baseCal.get(Calendar.DAY_OF_WEEK);
        boolean onWeekend =  dayOfWeek == Calendar.SATURDAY || dayOfWeek == Calendar.SUNDAY;

        //If it's on a holiday, increment and test again 
        //If it's on a weekend, increment necessary amount and test again
        if (offlimitDates.contains(baseCal.getTime()) || onWeekend)
            return false;
        else 
            return true;
    }


    /**
     * 
     * This method will calculate the next business day 
     * after the one input.  This leverages the isBusinessDay
     * heavily, so look at that documentation for further information.
     * 
     * @param startDate the Date of which you need the next business day.
     * @return The next business day.  I.E. it doesn't fall on a weekend, 
     * a holiday or the official observance of that holiday if it fell 
     * on a weekend. 
     *  
     */
    public static Date getNextBusinessDay(Date startDate)
    {
        //Increment the Date object by a Day and clear out hour/min/sec information
        Date nextDay = DateUtils.truncate(addDays(startDate, 1), Calendar.DATE);
        //If tomorrow is a valid business day, return it
        if (isBusinessDay(nextDay))
            return nextDay;
        //Else we recursively call our function until we find one. 
        else
            return getNextBusinessDay(nextDay);
    }

    /*
     * Based on a year, this will compute the actual dates of 
     * 
     * Holidays Accounted For: 
     * New Year's Day
     * Martin Luther King Jr. Day
     * President's Day 
     * Memorial Day 
     * Independence Day
     * Labor Day 
     * Columbus Day 
     * Veterans Day
     * Thanksgiving Day 
     * Christmas Day
     * 
     */
    private static List<Date> getOfflimitDates(int year)
    {
        List<Date> offlimitDates = new ArrayList<Date>();

        Calendar baseCalendar = GregorianCalendar.getInstance();
        baseCalendar.clear();

        //Add in the static dates for the year.
        //New years day
        baseCalendar.set(year, Calendar.JANUARY, 1);
        offlimitDates.add(offsetForWeekend(baseCalendar));

        //Independence Day
        baseCalendar.set(year, Calendar.JULY, 4);
        offlimitDates.add(offsetForWeekend(baseCalendar));

        //Vetrans Day
        baseCalendar.set(year, Calendar.NOVEMBER, 11);
        offlimitDates.add(offsetForWeekend(baseCalendar));

        //Christmas
        baseCalendar.set(year, Calendar.DECEMBER, 25);
        offlimitDates.add(offsetForWeekend(baseCalendar));

        //Now deal with floating holidays.
        //Martin Luther King Day 
        offlimitDates.add(calculateFloatingHoliday(3, Calendar.MONDAY, year, Calendar.JANUARY));

        //Presidents Day
        offlimitDates.add(calculateFloatingHoliday(3, Calendar.MONDAY, year, Calendar.FEBRUARY));

        //Memorial Day
        offlimitDates.add(calculateFloatingHoliday(0, Calendar.MONDAY, year, Calendar.MAY));

        //Labor Day
        offlimitDates.add(calculateFloatingHoliday(1, Calendar.MONDAY, year, Calendar.SEPTEMBER));

        //Columbus Day
        offlimitDates.add(calculateFloatingHoliday(2, Calendar.MONDAY, year, Calendar.OCTOBER));

        //Thanksgiving Day and Thanksgiving Friday
        Date thanksgiving = calculateFloatingHoliday(4, Calendar.THURSDAY, year, Calendar.NOVEMBER);
        offlimitDates.add(thanksgiving);
        offlimitDates.add(addDays(thanksgiving, 1));


        return offlimitDates;
    }


    /**
     * This method will take in the various parameters and return a Date objet
     * that represents that value. 
     * 
     * Ex. To get Martin Luther Kings BDay, which is the 3rd Monday of January, 
     * the method call woudl be:
     * 
     * calculateFloatingHoliday(3, Calendar.MONDAY, year, Calendar.JANUARY);
     * 
     * Reference material can be found at: 
     * http://michaelthompson.org/technikos/holidays.php#MemorialDay
     * 
     * @param nth 0 for Last, 1 for 1st, 2 for 2nd, etc. 
     * @param dayOfWeek Use Calendar.MODAY, Calendar.TUESDAY, etc. 
     * @param year 
     * @param month Use Calendar.JANUARY, etc. 
     * @return
     */
    private static Date calculateFloatingHoliday(int nth, int dayOfWeek, int year, int month)
    {
        Calendar baseCal = Calendar.getInstance();
        baseCal.clear();

        //Determine what the very earliest day this could occur.
        //If the value was 0 for the nth parameter, incriment to the following
        //month so that it can be subtracted alter. 
        baseCal.set(year, month + ((nth <= 0) ? 1 : 0), 1);
        Date baseDate = baseCal.getTime();

        //Figure out which day of the week that this "earliest" could occur on 
        //and then determine what the offset is for our day that we actually need. 
        int baseDayOfWeek = baseCal.get(Calendar.DAY_OF_WEEK);
        int fwd = dayOfWeek - baseDayOfWeek;

        //Based on the offset and the nth parameter, we are able to determine the offset of days and then 
        //adjust our base date. 
        return addDays(baseDate, (fwd + (nth - (fwd >= 0 ? 1 : 0)) * 7));
    }

    /*
     * If the given date falls on a weekend, the
     * method will adjust to the closest weekday.
     * I.E. If the date is on a Saturday, then the Friday
     * will be returned, if it's a Sunday, then Monday 
     * is returned.  
     */
    private static Date offsetForWeekend(Calendar baseCal)
    {
        Date returnDate = baseCal.getTime();
        if (baseCal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY)
        {
            if (log.isDebugEnabled())
                log.debug("Offsetting the Saturday by -1: " + returnDate);
            return addDays(returnDate, -1);
        }
        else if (baseCal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)
        {
            if (log.isDebugEnabled())
                log.debug("Offsetting the Sunday by +1: " + returnDate);
            return addDays(returnDate, 1);
        }
        else
            return returnDate;
    }

    /**
     * Private method simply adds 
     * @param dateToAdd
     * @param numberOfDay
     * @return
     */
    private static Date addDays(Date dateToAdd, int numberOfDay)
    {
        if (dateToAdd == null)
            throw new IllegalArgumentException("Date can't be null!");
        Calendar tempCal = Calendar.getInstance();
        tempCal.setTime(dateToAdd);
        tempCal.add(Calendar.DATE, numberOfDay);
        return tempCal.getTime();
    }
}
5
jnt30

jBPM (mindestens v3) hat eine gute Geschäftskalenderimplementierung

Wenn Sie nicht die ganze Abhängigkeit von JBPM wollen, können Sie einfach das calendar-Paket herausnehmen

3
Bozho

für Datumsberechnungen versuchen Sie joda-time.sourceforge.net

aber ich habe keine ahnung davon, was sie unter urlaubsgestaltung meinen. weil jedes Land unterschiedliche Feiertage hat. Aber versuchen Sie es zuerst, es ist gut für die Berechnung von Datum und Uhrzeit.

3
nightingale2k1

Ich würde vorschlagen, eine eigene inländische Ferienklasse zu erstellen, in der Sie die einzelnen Feiertage verwalten können. Alle Feiertage haben Regeln, an welchen Tagen sie stattfinden. Es ist leicht genug, diese Termine jedes Jahr zu programmieren.

Martin Luther King-Tag zum Beispiel:

private static Date holidayHumanRights(int parmYear)
    {
        Date tempDate = new Date(parmYear, 0, 1);   //January 1st...

        try
        {
            tempDate = getNextDayofWeek(tempDate, "Monday");

            //now point towards the 3rd Monday, which would be 2 weeks from
            //current Monday date...
            tempDate.advanceDays(2*7);
        }
        catch (Exception ex)
        {
            //throw or suppress the error, your choice
            System.err.println(ex.toString());
        }

        return tempDate;
    }
0
northpole

Ich habe kürzlich dieses Open Source-Projekt http://lamma.io entwickelt, das für die Datumsgenerierung gedacht ist. 

Zum Beispiel:

Date(2015, 10, 5) to Date(2015, 10, 15) by 2 except Weekends

wird nachgeben

List(2015-10-05, 2015-10-07, 2015-10-09, 2015-10-13, 2015-10-15)

Das Projekt ist unter DO WAS SIE ÖFFENTLICHE LIZENZEN WOLLEN willst, zögern Sie nicht, es zu verwenden/weiterzugeben :)

0
Max

Beim Nachdenken über das gleiche Problem habe ich einen Quartz Calendar herausgefunden. Es hat mehrere Probleme wie:

  1. Es ist ein Implementierungsteil einer Terminplanungsbibliothek - die Verwendung neben Quarz ist ebenso wie ein Feiertagskalender ein bisschen hackig.
  2. Es hat getNextIncludeTime Methode, aber keine getPrevIncludeTime.
  3. Es hat hässliche und inkonsistente API - AnnualCalendar hat Getter und Setter, der ArrayList nimmt, MonthlyCalendar hat Getter und Setter, der boolean [] nimmt, beide machen nur Klassenintern offen.
  4. Es gibt einige schlecht dokumentierte Probleme - Sie können Kalender verketten, aber die Reihenfolge der Verkettung ist wichtig. - DailyCalendar, der auf AnnualCalendar erstellt wurde, ist in Ordnung, der auf DailyCalendar erstellte AnnualCalendar bricht (hängt, glaube ich).

Trotzdem ist es das Beste, was ich finden konnte. Nehmen Sie also einfach den Quellcode, beheben Sie den Fehler und fügen Sie hinzu, was fehlt.

0
Tadeusz Kopec