一个很好的 Java 商务日历库?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1044921/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
A good Business calendar library in Java?
提问by HeDinges
Does anyone knows a good business calendarlibrary in java?
有谁知道java中一个好的商业日历库?
It should handle easy :) date calculations, taking holidays into account.
它应该处理简单的 :) 日期计算,将假期考虑在内。
Ideally, besides configuring holidaysand company off days, we should also be able to configure 'working hours' on a day basis so we can calculate SLA's and KPI's on working hours.
理想情况下,除了配置假期和公司休息日之外,我们还应该能够配置每天的“工作时间”,以便我们可以计算工作时间的 SLA 和 KPI。
I know something like this is part of jboss jBpm, but I was wondering if their was any other project doing this.
我知道这样的事情是 jboss jBpm 的一部分,但我想知道他们是否还有其他项目这样做。
Off course, open sourceis a big plus point!
当然,开源是一个很大的加分点!
采纳答案by eli
Check out this library, it has functionality for holidays and such, it's built around joda.
查看这个库,它具有假期等功能,它是围绕 joda 构建的。
回答by nightingale2k1
for date calculations try joda-time.sourceforge.net
对于日期计算,请尝试joda-time.sourceforge.net
but i have no idea about what you mean by configuring holidays. because each country has different holidays. but try that one first, it is good for date and time calculation.
但我不知道你说的配置假期是什么意思。因为每个国家都有不同的假期。但先试试那个,它有利于日期和时间计算。
回答by northpole
I would suggest creating your own domestic holiday class that you can manage each of the holidays in. All of the holidays have rules on which day they will be. It is easy enough to program for these dates each year.
我建议创建您自己的国内假期班,您可以管理每个假期。所有假期都有规定的日期。每年为这些日期编程是很容易的。
Martin Luther King day for example:
以马丁路德金纪念日为例:
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;
}
回答by jnt30
Below is a very longwinded answer. It's something that I put together for exactly this purpose. It's not super user friendly, but it should give you want you are looking for.
下面是一个非常冗长的答案。正是为了这个目的,我把它放在一起。它不是超级用户友好的,但它应该给你想要的东西。
It relies on the Apache commons project which can be acquired here: http://commons.apache.org/lang/
它依赖于 Apache 公共项目,可以从这里获得: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();
}
}
回答by Tadeusz Kopec
While thinking of the same problem I found out a Quartz Calendar. It has several problems like:
在考虑同样的问题时,我发现了Quartz Calendar。它有几个问题,例如:
- It is an implementation part of a scheduling library - using it apart from all quartz just as a holiday calendar is a bit hackish.
- It has
getNextIncludeTime
method but nogetPrevIncludeTime
. - It has ugly and inconsistent API - AnnualCalendarhas getter and setter that takes ArrayList, MonthlyCalendarhas getter and setter that takes boolean[], both of them just expose class internals.
- It has some poorly documented issues - you can chain calendars, but order of chaining is important - DailyCalendar created on AnnualCalendar is OK, AnnualCalendar created on DailyCalendar will break (hang, I think).
- 它是调度库的一个实现部分 - 将它与所有石英分开使用,就像假期日历一样有点hackish。
- 它有
getNextIncludeTime
方法但没有getPrevIncludeTime
。 - 它有丑陋且不一致的 API—— AnnualCalendar有采用 ArrayList 的 getter 和 setter,MonthlyCalendar有采用 boolean[] 的 getter 和 setter,它们都只公开类内部。
- 它有一些记录不足的问题 - 您可以链接日历,但链接的顺序很重要 - 在 AnnualCalendar 创建的 DailyCalendar 没问题,在 DailyCalendar 创建的 AnnualCalendar 会中断(我认为挂起)。
Still it is the best thing I could find. So maybe just take the source code, fix what's wrong and add what's missing?
仍然是我能找到的最好的东西。所以也许只是获取源代码,修复错误并添加缺少的内容?
回答by Bozho
jBPM(v3 at least) has a good business calendar implementation.
If you don't want the whole dependency on JBPM, I think you can take out just the calendar package
如果您不想完全依赖 JBPM,我认为您可以只取出日历包
回答by Max
I recently developed this open source project http://lamma.iowhich is designed for date generation.
我最近开发了这个开源项目http://lamma.io,它是为日期生成而设计的。
For example:
例如:
Date(2015, 10, 5) to Date(2015, 10, 15) by 2 except Weekends
will yield
会屈服
List(2015-10-05, 2015-10-07, 2015-10-09, 2015-10-13, 2015-10-15)
The project is licensed under DO WHAT YOU WANT TO PUBLIC LICENSE, so feel free to use / redistribute :)
该项目已根据 DO WHAT YOU WANT TO PUBLIC LICENSE 获得许可,因此请随意使用/重新分发 :)