代码之家  ›  专栏  ›  技术社区  ›  HeDinges

一个好的Java商业日历库?[关闭]

  •  33
  • HeDinges  · 技术社区  · 17 年前

    有人知道一件好事吗 商务日历 Java中的图书馆?

    它应该很容易处理:)日期计算,考虑到假期。

    理想情况下,另外 配置假日 公司休息日,我们也应该能够 配置“工作时间” '以天为基础,这样我们就可以计算工作时间的SLA和KPI。

    我知道这是JBossJBPM的一部分,但我想知道他们是否还有其他项目在做这个。

    偏离航向, 开放源代码 是个大加分!

    7 回复  |  直到 10 年前
        1
  •  18
  •   eli    16 年前

    看看这个图书馆,它有节日等功能,它是围绕着Joda建造的。

    http://objectlabkit.sourceforge.net/

        2
  •  5
  •   Mr Chow    12 年前

    下面是一个非常冗长的答案。正是为了这个目的,我把它放在一起。它不是超级用户友好型的,但它应该给你想要的你正在寻找。

    它依赖于Apache Commons项目,可以在这里获得: 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();
        }
    }
    
        3
  •  3
  •   nightingale2k1    17 年前

    对于日期计算,尝试 joda-time.sourceforge.net

    但我不知道配置假日是什么意思。因为每个国家都有不同的假期。但首先尝试一下,这对于日期和时间计算是很好的。

        4
  •  3
  •   Bozho    16 年前

    jBPM (至少v3)有一个好 business calendar implementation .

    如果你不想完全依赖jbpm,我想你可以去掉 calendar package

        5
  •  0
  •   northpole    17 年前

    我建议你创建一个你自己的家庭假期班,你可以在里面管理每个假期。所有的假期都有规定,他们将在哪一天。每年为这些日期编制程序都很容易。

    例如,马丁·路德·金日:

    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;
        }
    
        6
  •  0
  •   Tadeusz Kopec for Ukraine yespbs    16 年前

    当想到同样的问题时,我发现 Quartz Calendar . 它有几个问题,如:

    1. 它是调度库的一个实现部分——除了使用所有Quartz之外,使用它就像假日日历有点黑客。
    2. 它有 getNextIncludeTime 方法但不 getPrevIncludeTime .
    3. 它有丑陋和不一致的API- AnnualCalendar 有接受数组列表的getter和setter, MonthlyCalendar 具有获取布尔值[]的getter和setter,两者都只公开类内部。
    4. 它有一些文档记录不好的问题-您可以链接日历,但链接顺序很重要-在年鉴日历上创建的年鉴日历可以,在年鉴日历上创建的年鉴日历将中断(我认为挂起)。

    不过,这是我能找到的最好的东西。所以也许只需获取源代码,修复错误并添加缺少的内容?

        7
  •  0
  •   Max    12 年前

    我最近开发了这个开源项目 http://lamma.io 它是为生成日期而设计的。

    例如:

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

    将屈服

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

    该项目是根据“做你想公开的事情”许可的,因此请随意使用/重新发布:)