誰かがJavaの優れたビジネスカレンダーライブラリを知っていますか?
休日を考慮に入れて、:)日付の計算を簡単に処理する必要があります。
理想的には、休日の設定と会社の休業日の他に、'労働時間'を日単位で設定して、労働時間に関するSLAとKPIを計算できるようにする必要があります。
私はこのようなものがjboss jBpmの一部であることを知っていますが、彼らがこれを行う他のプロジェクトかどうか疑問に思っていました。
もちろん、オープンソースは大きなプラスポイントです!
このライブラリをチェックしてください。休日などの機能があり、jodaを中心に構築されています。
以下は非常に長続きする答えです。それはまさにこの目的のために私がまとめたものです。それは超ユーザーフレンドリーではありませんが、あなたが探しているものをあなたに与えてくれるはずです。
ここで取得できる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();
}
}
jBPM (少なくともv3)には優れた ビジネスカレンダーの実装 があります。
JBPMに完全に依存したくない場合は、 calendar package だけを取り出すことができると思います。
日付の計算には、 joda-time.sourceforge.net を試してください
しかし、私は休日を設定することによってあなたが何を意味するのか私にはわかりません。国によって休日が異なるためです。最初にそれを試してください。日付と時刻の計算に適しています。
それぞれの休日を管理できる独自の国内ホリデークラスを作成することをお勧めします。すべての休日には、どの曜日になるかについてのルールがあります。毎年これらの日付をプログラムするのは簡単です。
たとえば、マーティンルーサーキングの日:
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;
}
私は最近、このオープンソースプロジェクトを開発しました 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)
プロジェクトはDO WHAT YOU W WANT TO WANT YOU PUBLIC LICENSEの下でライセンスされているので、自由に使用/再配布してください:)
同じ問題を考えている間に、私は クォーツカレンダー を見つけました。次のようないくつかの問題があります。
getNextIncludeTime
メソッドはありますが、getPrevIncludeTime
はありません。それでも私が見つけた最高のものです。だから、たぶん、ソースコードを取り、何が問題なのかを修正し、足りないものを追加するだけなのでしょうか?