/**
*
*/
package com.widom.jyxd.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.widom.jyxd.common.Constant;
/**
* Date:2013-4-9
* <p>
* comment:计算工作日<br>
*
* <p>
*
* @author Liao, Ku-Cheng
*/
public final class DateCalculationUtil
{
private final static Log log = LogFactory.getLog(DateCalculationUtil.class);
/**
* 系统参数默认值,便于判断数据库中参数是否发生改变,如果发生变化,重新初始化国定假日,休息工作日数据。
*/
private static String HOLIDAY_PARAMVALUE = "";
/**
* 国定假日 如国庆假日等等
*/
private static List<Holiday> COUNTRY_HOLIDAY;
/**
* 休息工作日 ,因国定放假调休导致的周末工作情况
*/
private static List<Holiday> REST_WORK;
/**
* 当前时间,偏于缓存工作日的计算结果
*/
private static Calendar currentDate;
/**
* 计算时间的日期,结合currentDate,便于缓存计算结果。
*/
private static int beforeNum;
/**
* 时间运算结果
*/
private static Date result;
/**
* 返回一段时间之前的时间点,只计算工作日
*
* @param days
* 如果days小于等于0,返回当前日期
* @return
*/
public static Date getWorkTimeBefore(int days)
{
if (log.isDebugEnabled())
{
log.debug(" getWorkTimeBefore(" + days + ")");
}
Calendar current = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try
{
Date currentDate = sdf.parse(sdf.format(new Date()));
current.setTime(currentDate);
} catch (ParseException e)
{
log.warn("", e);
}
// 如果结果已经计算,直接返回
if (null != currentDate && null != result)
{
if (beforeNum == days && current.getTime().getTime() == currentDate.getTime().getTime())
{
return result;
}
}
else
{
Calendar clone = (Calendar) current.clone();
currentDate = clone;
// 采用递归方式计算前几天是否为工作日,如果是工作日,修改计算
while (days > 0)
{
current.add(Calendar.DATE, -1);
if (!isHoliday(current))
{
days--;
}
}
}
result = current.getTime();
if (log.isInfoEnabled())
{
log.info(" result : " + DateUtil.formateDate(result, "yyyy-MM-dd"));
}
return result;
}
/**
* 判断日期是否为假期<br>
* 1,计算当前日期是否为国定假日,如果是,将当前时间设定到国定假日的开始时间,同时返回true。否则返回false<br>
* 2,如果当前日期不是国定假日,计算当前日期是否为周末(包含休息工作日),如果当前日期是周末,返回true,否者返回fasle<br>
*
* @param cal
* @return
*/
private static boolean isHoliday(final Calendar cal)
{
return isCountryHoliday(cal) ? true : isWorkEnd(cal);
}
/**
* 是否为休息工作日<br>
* 1,获取休息工作日的配置时间<br>
* 2,判断当前时间是否包含在休息工作日当中,如果在休息工作日当中,返回true,否者返回false.
*
* @param cal
* @return
*/
private static boolean isRestForWork(final Calendar cal)
{
if (log.isDebugEnabled())
{
log.debug("isCountryHoliday (" + DateUtil.formateDate(cal.getTime(), "yyyy-MM-dd") + ")");
}
String key = "key : " + Constant.SYSTEM + " key : " + Constant.HOLIDAY;
Object data = CacheUtil.get(key);
String paramValue = null;
if (null == data)
{
paramValue = SystemParamUtil.getSystemParam(Constant.SYSTEM, Constant.HOLIDAY).trim();
CacheUtil.put(key, paramValue);
}
else
{
paramValue = data.toString();
}
if (!HOLIDAY_PARAMVALUE.equals(paramValue))
{
HOLIDAY_PARAMVALUE = paramValue;
initHoliday(paramValue);
}
return iteratorRestForWork(cal);
}
/**
* 遍历休息工作日,判断日期是否包含在休息工作日当中
*
* @param cal
* @return
*/
private static boolean iteratorRestForWork(Calendar cal)
{
if (null != REST_WORK)
{
for (Holiday holiday : REST_WORK)
{
if (holiday.isContain(cal.getTime()))
{
cal.setTime(holiday.startDate);
return true;
}
}
}
return false;
}
/**
* 是否为周末<br>
* 如果为周末,检查是否为休息工作日.返回true,同时将时间移动到周末开始时间,否则返回fasle
*
* @param cal
* @return
*/
private static boolean isWorkEnd(final Calendar cal)
{
if (log.isDebugEnabled())
{
log.debug("isWorkEnd ()");
log.debug(DateUtil.formateDate(cal.getTime(), "yyyy-MM-dd"));
}
int num = cal.get(Calendar.DAY_OF_WEEK);
if (num == Calendar.SUNDAY)
{
if (isRestForWork(cal))
{
return false;
}
cal.add(Calendar.DATE, -1);
return true;
}
if (num == Calendar.SATURDAY)
{
if (isRestForWork(cal))
{
return false;
}
return true;
}
return false;
}
/**
* 是否为国定假日,如果是国定假日,将日期移动到国定假日开始的日期,返回true,否则返回false;
*
* @param cal
* @return
*/
private static boolean isCountryHoliday(final Calendar cal)
{
if (log.isDebugEnabled())
{
log.debug("isCountryHoliday (" + DateUtil.formateDate(cal.getTime(), "yyyy-MM-dd") + ")");
}
String key = "key : " + Constant.SYSTEM + " key : " + Constant.HOLIDAY;
Object data = CacheUtil.get(key);
String paramValue = null;
if (null == data)
{
paramValue = SystemParamUtil.getSystemParam(Constant.SYSTEM, Constant.HOLIDAY).trim();
CacheUtil.put(key, paramValue);
}
else
{
paramValue = data.toString();
}
if (!HOLIDAY_PARAMVALUE.equals(paramValue))
{
HOLIDAY_PARAMVALUE = paramValue;
initHoliday(paramValue);
}
return iteratorHoliday(cal);
}
/**
* 遍历国定假日,如果当前日期在国定假日之内,将当前时间移动到假期的开始时间
*
* @param cal
*/
private static boolean iteratorHoliday(final Calendar cal)
{
if (null != COUNTRY_HOLIDAY)
{
for (Holiday holiday : COUNTRY_HOLIDAY)
{
if (holiday.isContain(cal.getTime()))
{
cal.setTime(holiday.startDate);
return true;
}
}
}
return false;
}
/**
* 初始国定假期数据
*/
private static void initHoliday(String paramValue)
{
if (null == paramValue)
{
COUNTRY_HOLIDAY = Collections.emptyList();
}
try
{
String[] sts = paramValue.split(";");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
List<Holiday> result = new LinkedList<Holiday>();
List<Holiday> rest = new LinkedList<Holiday>();
for (String st : sts)
{
if (st.contains("@"))
{
String[] daysStr = st.split("@");
if (daysStr.length == 2)
{
Date startDate = sdf.parse(daysStr[0]);
Date endDate = sdf.parse(daysStr[1]);
Holiday holiday = new Holiday(startDate, endDate);
result.add(holiday);
}
}
else if (st.contains("#"))
{
String[] daysStr = st.split("#");
if (daysStr.length == 2)
{
Date startDate = sdf.parse(daysStr[0]);
Date endDate = sdf.parse(daysStr[1]);
Holiday holiday = new Holiday(startDate, endDate);
rest.add(holiday);
}
}
}
COUNTRY_HOLIDAY = result;
REST_WORK = rest;
} catch (Exception e)
{
log.error("", e);
}
}
/**
* 国定假日静态类 Date:2013-4-11
* <p>
* comment: 包含假日的开始时间,结束时间,如果国定假日只有1天,则开始时间与结束时间相同。同时适用周末工作日
* <p>
*
* @author Liao, Ku-Cheng Copyright 2011 sh-tobacco & wisdom
*/
private static class Holiday
{
/**
* 开始时间
*/
private Date startDate;
/**
* 结束时间
*/
private Date endDate;
public Holiday(Date start, Date end)
{
startDate = start;
endDate = end;
}
/**
* 是否在假期内
*
* @param date
* @return
*/
public boolean isContain(Date date)
{
return compareTime(startDate, date) && compareTime(date, endDate);
}
/**
* 比较时间
*
* @param start
* @param end
* @return
*/
private boolean compareTime(Date start , Date end)
{
long startTime = start.getTime();
long endTime = end.getTime();
return startTime <= endTime;
}
}
/**
* 计算两个日期之间的工作日(只排除周末日期)
*
* @param start
* @param end
* @return
*/
public static int getWorkDays(Calendar start , Calendar end)
{
if (start.getTime().getTime() > end.getTime().getTime())
{
return -1;
}
int startDays = nextMonday(start);
int endDays = nextMonday(end);
int result = startDays - endDays;
int startYear = start.get(Calendar.YEAR);
int endYear = end.get(Calendar.YEAR);
int days = end.get(Calendar.DAY_OF_YEAR)-start.get(Calendar.DAY_OF_YEAR);
// 计算跨年日期之间的天数
if (startYear != endYear)
{
int yearNum = endYear - startYear;
for (int i = 0; i < yearNum; i++)
{
days += start.getActualMaximum(Calendar.DAY_OF_YEAR);
start.add(Calendar.YEAR, 1);
}
}
result += days / 7 * 5;
return result;
}
/**
* 计算当前日期到下一个星期一的时间天数,同时将时间修改为星期一的日期
*
* @param date
* @return
*/
private static int nextMonday(Calendar date)
{
int result = 0;
//将时间移动到下一个星期一
switch (date.get(Calendar.DAY_OF_WEEK))
{
case Calendar.FRIDAY:
result = 1;
break;
case Calendar.THURSDAY:
result = 2;
break;
case Calendar.WEDNESDAY:
result = 3;
break;
case Calendar.TUESDAY:
result = 4;
break;
}
date.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
date.add(Calendar.DAY_OF_YEAR, 7);
return result;
}
public static void main(String[] args) throws ParseException
{
//
// System.out.println(DateCalculationUtil.getWorkTimeBefore(6));
// System.out.println(DateCalculationUtil.getWorkTimeBefore(6));
Calendar current = Calendar.getInstance();
Calendar start = Calendar.getInstance();
String date = "2013-03-12";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date startDate = sdf.parse(date);
start.setTime(startDate);
System.out.println(DateCalculationUtil.getWorkDays(start, current));
}
}
*
*/
package com.widom.jyxd.util;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.widom.jyxd.common.Constant;
/**
* Date:2013-4-9
* <p>
* comment:计算工作日<br>
*
* <p>
*
* @author Liao, Ku-Cheng
*/
public final class DateCalculationUtil
{
private final static Log log = LogFactory.getLog(DateCalculationUtil.class);
/**
* 系统参数默认值,便于判断数据库中参数是否发生改变,如果发生变化,重新初始化国定假日,休息工作日数据。
*/
private static String HOLIDAY_PARAMVALUE = "";
/**
* 国定假日 如国庆假日等等
*/
private static List<Holiday> COUNTRY_HOLIDAY;
/**
* 休息工作日 ,因国定放假调休导致的周末工作情况
*/
private static List<Holiday> REST_WORK;
/**
* 当前时间,偏于缓存工作日的计算结果
*/
private static Calendar currentDate;
/**
* 计算时间的日期,结合currentDate,便于缓存计算结果。
*/
private static int beforeNum;
/**
* 时间运算结果
*/
private static Date result;
/**
* 返回一段时间之前的时间点,只计算工作日
*
* @param days
* 如果days小于等于0,返回当前日期
* @return
*/
public static Date getWorkTimeBefore(int days)
{
if (log.isDebugEnabled())
{
log.debug(" getWorkTimeBefore(" + days + ")");
}
Calendar current = Calendar.getInstance();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try
{
Date currentDate = sdf.parse(sdf.format(new Date()));
current.setTime(currentDate);
} catch (ParseException e)
{
log.warn("", e);
}
// 如果结果已经计算,直接返回
if (null != currentDate && null != result)
{
if (beforeNum == days && current.getTime().getTime() == currentDate.getTime().getTime())
{
return result;
}
}
else
{
Calendar clone = (Calendar) current.clone();
currentDate = clone;
// 采用递归方式计算前几天是否为工作日,如果是工作日,修改计算
while (days > 0)
{
current.add(Calendar.DATE, -1);
if (!isHoliday(current))
{
days--;
}
}
}
result = current.getTime();
if (log.isInfoEnabled())
{
log.info(" result : " + DateUtil.formateDate(result, "yyyy-MM-dd"));
}
return result;
}
/**
* 判断日期是否为假期<br>
* 1,计算当前日期是否为国定假日,如果是,将当前时间设定到国定假日的开始时间,同时返回true。否则返回false<br>
* 2,如果当前日期不是国定假日,计算当前日期是否为周末(包含休息工作日),如果当前日期是周末,返回true,否者返回fasle<br>
*
* @param cal
* @return
*/
private static boolean isHoliday(final Calendar cal)
{
return isCountryHoliday(cal) ? true : isWorkEnd(cal);
}
/**
* 是否为休息工作日<br>
* 1,获取休息工作日的配置时间<br>
* 2,判断当前时间是否包含在休息工作日当中,如果在休息工作日当中,返回true,否者返回false.
*
* @param cal
* @return
*/
private static boolean isRestForWork(final Calendar cal)
{
if (log.isDebugEnabled())
{
log.debug("isCountryHoliday (" + DateUtil.formateDate(cal.getTime(), "yyyy-MM-dd") + ")");
}
String key = "key : " + Constant.SYSTEM + " key : " + Constant.HOLIDAY;
Object data = CacheUtil.get(key);
String paramValue = null;
if (null == data)
{
paramValue = SystemParamUtil.getSystemParam(Constant.SYSTEM, Constant.HOLIDAY).trim();
CacheUtil.put(key, paramValue);
}
else
{
paramValue = data.toString();
}
if (!HOLIDAY_PARAMVALUE.equals(paramValue))
{
HOLIDAY_PARAMVALUE = paramValue;
initHoliday(paramValue);
}
return iteratorRestForWork(cal);
}
/**
* 遍历休息工作日,判断日期是否包含在休息工作日当中
*
* @param cal
* @return
*/
private static boolean iteratorRestForWork(Calendar cal)
{
if (null != REST_WORK)
{
for (Holiday holiday : REST_WORK)
{
if (holiday.isContain(cal.getTime()))
{
cal.setTime(holiday.startDate);
return true;
}
}
}
return false;
}
/**
* 是否为周末<br>
* 如果为周末,检查是否为休息工作日.返回true,同时将时间移动到周末开始时间,否则返回fasle
*
* @param cal
* @return
*/
private static boolean isWorkEnd(final Calendar cal)
{
if (log.isDebugEnabled())
{
log.debug("isWorkEnd ()");
log.debug(DateUtil.formateDate(cal.getTime(), "yyyy-MM-dd"));
}
int num = cal.get(Calendar.DAY_OF_WEEK);
if (num == Calendar.SUNDAY)
{
if (isRestForWork(cal))
{
return false;
}
cal.add(Calendar.DATE, -1);
return true;
}
if (num == Calendar.SATURDAY)
{
if (isRestForWork(cal))
{
return false;
}
return true;
}
return false;
}
/**
* 是否为国定假日,如果是国定假日,将日期移动到国定假日开始的日期,返回true,否则返回false;
*
* @param cal
* @return
*/
private static boolean isCountryHoliday(final Calendar cal)
{
if (log.isDebugEnabled())
{
log.debug("isCountryHoliday (" + DateUtil.formateDate(cal.getTime(), "yyyy-MM-dd") + ")");
}
String key = "key : " + Constant.SYSTEM + " key : " + Constant.HOLIDAY;
Object data = CacheUtil.get(key);
String paramValue = null;
if (null == data)
{
paramValue = SystemParamUtil.getSystemParam(Constant.SYSTEM, Constant.HOLIDAY).trim();
CacheUtil.put(key, paramValue);
}
else
{
paramValue = data.toString();
}
if (!HOLIDAY_PARAMVALUE.equals(paramValue))
{
HOLIDAY_PARAMVALUE = paramValue;
initHoliday(paramValue);
}
return iteratorHoliday(cal);
}
/**
* 遍历国定假日,如果当前日期在国定假日之内,将当前时间移动到假期的开始时间
*
* @param cal
*/
private static boolean iteratorHoliday(final Calendar cal)
{
if (null != COUNTRY_HOLIDAY)
{
for (Holiday holiday : COUNTRY_HOLIDAY)
{
if (holiday.isContain(cal.getTime()))
{
cal.setTime(holiday.startDate);
return true;
}
}
}
return false;
}
/**
* 初始国定假期数据
*/
private static void initHoliday(String paramValue)
{
if (null == paramValue)
{
COUNTRY_HOLIDAY = Collections.emptyList();
}
try
{
String[] sts = paramValue.split(";");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
List<Holiday> result = new LinkedList<Holiday>();
List<Holiday> rest = new LinkedList<Holiday>();
for (String st : sts)
{
if (st.contains("@"))
{
String[] daysStr = st.split("@");
if (daysStr.length == 2)
{
Date startDate = sdf.parse(daysStr[0]);
Date endDate = sdf.parse(daysStr[1]);
Holiday holiday = new Holiday(startDate, endDate);
result.add(holiday);
}
}
else if (st.contains("#"))
{
String[] daysStr = st.split("#");
if (daysStr.length == 2)
{
Date startDate = sdf.parse(daysStr[0]);
Date endDate = sdf.parse(daysStr[1]);
Holiday holiday = new Holiday(startDate, endDate);
rest.add(holiday);
}
}
}
COUNTRY_HOLIDAY = result;
REST_WORK = rest;
} catch (Exception e)
{
log.error("", e);
}
}
/**
* 国定假日静态类 Date:2013-4-11
* <p>
* comment: 包含假日的开始时间,结束时间,如果国定假日只有1天,则开始时间与结束时间相同。同时适用周末工作日
* <p>
*
* @author Liao, Ku-Cheng Copyright 2011 sh-tobacco & wisdom
*/
private static class Holiday
{
/**
* 开始时间
*/
private Date startDate;
/**
* 结束时间
*/
private Date endDate;
public Holiday(Date start, Date end)
{
startDate = start;
endDate = end;
}
/**
* 是否在假期内
*
* @param date
* @return
*/
public boolean isContain(Date date)
{
return compareTime(startDate, date) && compareTime(date, endDate);
}
/**
* 比较时间
*
* @param start
* @param end
* @return
*/
private boolean compareTime(Date start , Date end)
{
long startTime = start.getTime();
long endTime = end.getTime();
return startTime <= endTime;
}
}
/**
* 计算两个日期之间的工作日(只排除周末日期)
*
* @param start
* @param end
* @return
*/
public static int getWorkDays(Calendar start , Calendar end)
{
if (start.getTime().getTime() > end.getTime().getTime())
{
return -1;
}
int startDays = nextMonday(start);
int endDays = nextMonday(end);
int result = startDays - endDays;
int startYear = start.get(Calendar.YEAR);
int endYear = end.get(Calendar.YEAR);
int days = end.get(Calendar.DAY_OF_YEAR)-start.get(Calendar.DAY_OF_YEAR);
// 计算跨年日期之间的天数
if (startYear != endYear)
{
int yearNum = endYear - startYear;
for (int i = 0; i < yearNum; i++)
{
days += start.getActualMaximum(Calendar.DAY_OF_YEAR);
start.add(Calendar.YEAR, 1);
}
}
result += days / 7 * 5;
return result;
}
/**
* 计算当前日期到下一个星期一的时间天数,同时将时间修改为星期一的日期
*
* @param date
* @return
*/
private static int nextMonday(Calendar date)
{
int result = 0;
//将时间移动到下一个星期一
switch (date.get(Calendar.DAY_OF_WEEK))
{
case Calendar.FRIDAY:
result = 1;
break;
case Calendar.THURSDAY:
result = 2;
break;
case Calendar.WEDNESDAY:
result = 3;
break;
case Calendar.TUESDAY:
result = 4;
break;
}
date.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
date.add(Calendar.DAY_OF_YEAR, 7);
return result;
}
public static void main(String[] args) throws ParseException
{
//
// System.out.println(DateCalculationUtil.getWorkTimeBefore(6));
// System.out.println(DateCalculationUtil.getWorkTimeBefore(6));
Calendar current = Calendar.getInstance();
Calendar start = Calendar.getInstance();
String date = "2013-03-12";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
Date startDate = sdf.parse(date);
start.setTime(startDate);
System.out.println(DateCalculationUtil.getWorkDays(start, current));
}
}