web-dev-qa-db-fra.com

Une bonne bibliothèque de calendriers Business en Java?

Est-ce que quelqu'un connaît un bon calendrier d'affaires bibliothèque en java? 

Il convient de manipuler facilement :) les calculs de date, en tenant compte des vacances.

Idéalement, outre la configuration des jours fériés et des jours fériés, nous devrions également être en mesure de configurer les 'heures de travail ' de manière à pouvoir calculer les SLA et les KPI sur les heures de travail.

Je sais que quelque chose comme cela fait partie de jboss jBpm, mais je me demandais si un autre projet faisait cela.

Bien sûr, open source est un gros avantage! 

33
HeDinges

Découvrez cette bibliothèque, elle a des fonctionnalités pour les vacances et autres, elle est construite autour de joda.

http://objectlabkit.sourceforge.net/

18
eli

Vous trouverez ci-dessous une réponse très longue. C'est quelque chose que j'ai mis en place dans ce but précis. Ce n’est pas très convivial, mais cela devrait vous donner le goût que vous recherchez.

Il s’appuie sur le projet Apache commons qui peut être acquis ici: 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 (v3 au moins) a une bonne implémentation du calendrier business

Si vous ne voulez pas toute la dépendance sur JBPM, je pense que vous pouvez retirer uniquement le paquetage calendar

3
Bozho

pour les calculs de date, essayez joda-time.sourceforge.net

mais je n'ai aucune idée de ce que vous entendez par la configuration des vacances. parce que chaque pays a des vacances différentes. Mais essayez-le d'abord, c'est bon pour le calcul de la date et de l'heure.

3
nightingale2k1

Je suggérerais de créer votre propre classe de vacances domestiques dans laquelle vous pourrez gérer chacune des vacances. Toutes les vacances ont des règles pour le jour où elles se dérouleront. Il est assez facile de programmer ces dates chaque année.

Journée Martin Luther King par exemple:

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

J'ai récemment développé ce projet open source http://lamma.io qui est conçu pour la génération de dates. 

Par exemple:

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

va céder

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

Le projet est sous licence LIRE CE QUE VOUS VOULEZ PUBLIER, alors n'hésitez pas à utiliser/redistribuer :)

0
Max

En pensant au même problème, j'ai découvert un Calendrier Quartz . Il a plusieurs problèmes comme:

  1. Il s’agit d’une partie de la mise en œuvre d’une bibliothèque d’ordonnancement - l’utiliser en dehors de tout quartz comme un calendrier de vacances est un peu fictif.
  2. Il a la méthode getNextIncludeTime mais pas getPrevIncludeTime.
  3. Il a des API vilaines et incohérentes - AnnualCalendar a un getter et un setter qui prend ArrayList, MonthlyCalendar un getter et un setter qui prend un booléen [], les deux exposant juste les internes de la classe.
  4. Il y a quelques problèmes mal documentés - vous pouvez chaîner des calendriers, mais l'ordre de chaînage est important - DailyCalendar créé sur AnnualCalendar est OK, AnnualCalendar créé sur DailyCalendar va se rompre (se bloquer, je pense).

Pourtant, c'est la meilleure chose que j'ai pu trouver. Alors peut-être juste prendre le code source, réparer ce qui ne va pas et ajouter ce qui manque?

0
Tadeusz Kopec