對於工作日處理相對來說還是比較簡單的,不外乎就是週末判斷和假期判斷。
不過,有些人會把它們寫死在類裏面,看以下代碼:
耦合性較強的代碼:
- public class WeekdayUtil {
- /**
- * @title 判斷兩個日期是否在指定工作日內
- * @detail (只計算週六和週日)
- * 例如:前時間2008-12-05,後時間2008-12-11
- * @author chanson
- * @param beforeDate 前時間
- * @param afterDate 後時間
- * @param deadline 最多相隔時間
- * @return 是的話,返回true,否則返回false
- */
- public boolean compareWeekday(String beforeDate, String afterDate, int deadline) {
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
- try {
- Date d1 = sdf.parse(beforeDate);
- Date d2 = sdf.parse(afterDate);
- //工作日
- int workDay = 0;
- GregorianCalendar gc = new GregorianCalendar();
- gc.setTime(d1);
- // 兩個日期相差的天數
- long time = d2.getTime() - d1.getTime();
- long day = time / 3600000 / 24 + 1;
- if(day < 0){
- //如果前日期大於後日期,將返回false
- return false;
- }
- for (int i = 0; i < day; i++) {
- if(isWeekday(gc)){
- workDay++;
- // System.out.println(gc.getTime());
- }
- //往後加1天
- gc.add(GregorianCalendar.DATE, 1);
- }
- return workDay <= deadline;
- } catch (Exception e) {
- e.printStackTrace();
- return false;
- }
- }
- /**
- * @title 判斷是否爲工作日
- * @detail 工作日計算:
- * 1、正常工作日,並且爲非假期
- * 2、週末被調整成工作日
- * @author chanson
- * @param date 日期
- * @return 是工作日返回true,非工作日返回false
- */
- public boolean isWeekday(GregorianCalendar calendar){
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
- if (calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SATURDAY
- && calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SUNDAY){
- //平時
- return !getWeekdayIsHolidayList().contains(sdf.format(calendar.getTime()));
- }else{
- //週末
- return getWeekendIsWorkDateList().contains(sdf.format(calendar.getTime()));
- }
- }
- /**
- * @title 獲取週六和週日是工作日的情況(手工維護)
- * 注意,日期必須寫全:
- * 2009-1-4必須寫成:2009-01-04
- * @author chanson
- * @return 週末是工作日的列表
- */
- public List getWeekendIsWorkDateList(){
- List list = new ArrayList();
- list.add("2009-01-04");
- list.add("2009-01-24");
- list.add("2009-02-01");
- list.add("2009-05-31");
- list.add("2009-09-27");
- list.add("2009-10-10");
- return list;
- }
- /**
- * @title 獲取週一到週五是假期的情況(手工維護)
- * 注意,日期必須寫全:
- * 2009-1-4必須寫成:2009-01-04
- * @author chanson
- * @return 平時是假期的列表
- */
- public List getWeekdayIsHolidayList(){
- List list = new ArrayList();
- list.add("2009-01-29");
- list.add("2009-01-30");
- list.add("2009-04-06");
- list.add("2009-05-01");
- list.add("2009-05-28");
- list.add("2009-05-29");
- list.add("2009-10-01");
- list.add("2009-10-02");
- list.add("2009-10-05");
- list.add("2009-10-06");
- list.add("2009-10-07");
- list.add("2009-10-08");
- return list;
- }
- public static void main(String[] args) {
- WeekdayUtil dateUtils = new WeekdayUtil();
- boolean ok = dateUtils.compareWeekday("2009-10-1", "2009-10-15", 5);
- System.out.println("是否在五個工作日內:" + ok);
- }
- }
public class WeekdayUtil {
/**
* @title 判斷兩個日期是否在指定工作日內
* @detail (只計算週六和週日)
* 例如:前時間2008-12-05,後時間2008-12-11
* @author chanson
* @param beforeDate 前時間
* @param afterDate 後時間
* @param deadline 最多相隔時間
* @return 是的話,返回true,否則返回false
*/
public boolean compareWeekday(String beforeDate, String afterDate, int deadline) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
try {
Date d1 = sdf.parse(beforeDate);
Date d2 = sdf.parse(afterDate);
//工作日
int workDay = 0;
GregorianCalendar gc = new GregorianCalendar();
gc.setTime(d1);
// 兩個日期相差的天數
long time = d2.getTime() - d1.getTime();
long day = time / 3600000 / 24 + 1;
if(day < 0){
//如果前日期大於後日期,將返回false
return false;
}
for (int i = 0; i < day; i++) {
if(isWeekday(gc)){
workDay++;
// System.out.println(gc.getTime());
}
//往後加1天
gc.add(GregorianCalendar.DATE, 1);
}
return workDay <= deadline;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* @title 判斷是否爲工作日
* @detail 工作日計算:
* 1、正常工作日,並且爲非假期
* 2、週末被調整成工作日
* @author chanson
* @param date 日期
* @return 是工作日返回true,非工作日返回false
*/
public boolean isWeekday(GregorianCalendar calendar){
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
if (calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SATURDAY
&& calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SUNDAY){
//平時
return !getWeekdayIsHolidayList().contains(sdf.format(calendar.getTime()));
}else{
//週末
return getWeekendIsWorkDateList().contains(sdf.format(calendar.getTime()));
}
}
/**
* @title 獲取週六和週日是工作日的情況(手工維護)
* 注意,日期必須寫全:
* 2009-1-4必須寫成:2009-01-04
* @author chanson
* @return 週末是工作日的列表
*/
public List getWeekendIsWorkDateList(){
List list = new ArrayList();
list.add("2009-01-04");
list.add("2009-01-24");
list.add("2009-02-01");
list.add("2009-05-31");
list.add("2009-09-27");
list.add("2009-10-10");
return list;
}
/**
* @title 獲取週一到週五是假期的情況(手工維護)
* 注意,日期必須寫全:
* 2009-1-4必須寫成:2009-01-04
* @author chanson
* @return 平時是假期的列表
*/
public List getWeekdayIsHolidayList(){
List list = new ArrayList();
list.add("2009-01-29");
list.add("2009-01-30");
list.add("2009-04-06");
list.add("2009-05-01");
list.add("2009-05-28");
list.add("2009-05-29");
list.add("2009-10-01");
list.add("2009-10-02");
list.add("2009-10-05");
list.add("2009-10-06");
list.add("2009-10-07");
list.add("2009-10-08");
return list;
}
public static void main(String[] args) {
WeekdayUtil dateUtils = new WeekdayUtil();
boolean ok = dateUtils.compareWeekday("2009-10-1", "2009-10-15", 5);
System.out.println("是否在五個工作日內:" + ok);
}
}
這個類相對來說寫得就比較死了——太不遵循OCP原則了吧。
有人說,把工作日配置在數據庫中,而且還能根據一定的規律推算出假期來——很厲害,一次生成50年的工作日。但國家
的假期是會變的,比如取消5.1長假就是一個很典型的例子,總不至於每次都得改算法吧。搞不準過2年後,連10.1長假都
沒了。
相對來說,我覺得還是放在XML文件中配置比較靈活。那有人會懷疑說,每次都得訪問XML會不會有效率問題。
當然,如果你項目中使用它非常頻繁的話,那就把數據放在內存中吧。每次修改該XML文件的時候刷新內存就可以了。
【改造】
1、引入XML
- <?xml version="1.0" encoding="utf-8"?>
- <root>
- <validation>
- <list>
- <!-- 非補報報文的交易時間必須在5個工作日內 -->
- <key>EXCH_DATE_CHECK</key>
- <value>5</value>
- </list>
- <list>
- <!-- 回執處理必須在5個工作日內 -->
- <key>REC_DATE_CHECK</key>
- <value>5</value>
- </list>
- </validation>
- <!-- 工作日是假期的情況 -->
- <weekday>
- <holiday_list>
- <date>2009-01-29</date>
- <date>2009-01-30</date>
- <date>2009-04-06</date>
- <date>2009-05-01</date>
- <date>2009-05-28</date>
- <date>2009-05-29</date>
- <date>2009-10-01</date>
- <date>2009-10-02</date>
- <date>2009-10-05</date>
- <date>2009-10-06</date>
- <date>2009-10-07</date>
- <date>2009-10-08</date>
- </holiday_list>
- </weekday>
- <!-- 週末是工作日的情況 -->
- <weekend>
- <weekday_list>
- <date>2009-01-04</date>
- <date>2009-01-24</date>
- <date>2009-02-01</date>
- <date>2009-05-31</date>
- <date>2009-09-27</date>
- <date>2009-10-10</date>
- </weekday_list>
- </weekend>
- </root>
<?xml version="1.0" encoding="utf-8"?>
<root>
<validation>
<list>
<!-- 非補報報文的交易時間必須在5個工作日內 -->
<key>EXCH_DATE_CHECK</key>
<value>5</value>
</list>
<list>
<!-- 回執處理必須在5個工作日內 -->
<key>REC_DATE_CHECK</key>
<value>5</value>
</list>
</validation>
<!-- 工作日是假期的情況 -->
<weekday>
<holiday_list>
<date>2009-01-29</date>
<date>2009-01-30</date>
<date>2009-04-06</date>
<date>2009-05-01</date>
<date>2009-05-28</date>
<date>2009-05-29</date>
<date>2009-10-01</date>
<date>2009-10-02</date>
<date>2009-10-05</date>
<date>2009-10-06</date>
<date>2009-10-07</date>
<date>2009-10-08</date>
</holiday_list>
</weekday>
<!-- 週末是工作日的情況 -->
<weekend>
<weekday_list>
<date>2009-01-04</date>
<date>2009-01-24</date>
<date>2009-02-01</date>
<date>2009-05-31</date>
<date>2009-09-27</date>
<date>2009-10-10</date>
</weekday_list>
</weekend>
</root>
注:該XML文件放在src/config下。
2、增加解析XML的方法
- public class Dom4JUtil {
- private final static String BASE_PATH = "/config/";
- public String getConfFile(String file) {
- URL confURL = getClass().getClassLoader().getResource(file);
- if (confURL == null)
- confURL = getClass().getClassLoader().getResource(
- "META-INF/" + file);
- if (confURL == null)
- confURL = Thread.currentThread().getContextClassLoader()
- .getResource(file);
- if (confURL == null) {
- System.err.println(" cann't find config file:-->" + file);
- } else {
- String filePath = confURL.getFile();
- filePath = filePath.replaceAll("%20", " ");
- File file1 = new File(filePath);
- if (file1.isFile())
- return filePath;
- }
- return null;
- }
- /**
- * @title 獲取工作日相關配置
- * @author chanson
- * @return
- */
- public WeekdayVO getWeekdayConfig(){
- Map validateMap = new HashMap();
- List weekendIsWeekdayList = new ArrayList();
- List weekdayIsHolidayList = new ArrayList();
- //1、放到web工程
- File f = new File(getConfFile(BASE_PATH + "weekday.xml"));
- //2、application測試
- //String file = "D:/workspace/test/src/config/weekday.xml";
- //File f = new File(file);
- SAXReader reader = new SAXReader();
- try{
- Document doc = reader.read(f);
- Element root = doc.getRootElement();
- //===================================
- //工作日校驗相關屬性
- //===================================
- Element validationElement = root.element("validation");
- Element listElement;
- for(Iterator i = validationElement.elementIterator("list");i.hasNext();){
- listElement = (Element)i.next();
- validateMap.put((String) listElement.elementText("key"),
- (String)listElement.elementText("value"));
- }
- //===================================
- //工作日是假期的列表
- //===================================
- Element weekdayElement = root.element("weekday");
- Element holidayListElement = weekdayElement.element("holiday_list");
- Element holidayValueElement = null;
- for(Iterator i = holidayListElement.elementIterator("date");i.hasNext();){
- holidayValueElement = (Element)i.next();
- weekdayIsHolidayList.add((String)holidayValueElement.getText());
- }
- //===================================
- //週末是工作日的列表
- //===================================
- Element weekendElement = root.element("weekend");
- Element weekdayListElement = weekendElement.element("weekday_list");
- Element weekdayValueElement = null;
- for(Iterator i = weekdayListElement.elementIterator("date");i.hasNext();){
- weekdayValueElement = (Element)i.next();
- weekendIsWeekdayList.add((String)weekdayValueElement.getText());
- }
- WeekdayVO vo = new WeekdayVO();
- vo.setValidateMap(validateMap);
- vo.setWeekdayIsHolidayList(weekdayIsHolidayList);
- vo.setWeekendIsWeekdayList(weekendIsWeekdayList);
- return vo;
- }catch(Exception e){
- e.printStackTrace();
- return null;
- }
- }
- public static void main(String[] args) {
- Dom4JUtil dom4JUtil = new Dom4JUtil();
- WeekdayVO vo = dom4JUtil.getWeekdayConfig();
- System.out.println(vo.getWeekdayIsHolidayList());
- System.out.println(vo.getWeekendIsWeekdayList());
- }
- }
public class Dom4JUtil {
private final static String BASE_PATH = "/config/";
public String getConfFile(String file) {
URL confURL = getClass().getClassLoader().getResource(file);
if (confURL == null)
confURL = getClass().getClassLoader().getResource(
"META-INF/" + file);
if (confURL == null)
confURL = Thread.currentThread().getContextClassLoader()
.getResource(file);
if (confURL == null) {
System.err.println(" cann't find config file:-->" + file);
} else {
String filePath = confURL.getFile();
filePath = filePath.replaceAll("%20", " ");
File file1 = new File(filePath);
if (file1.isFile())
return filePath;
}
return null;
}
/**
* @title 獲取工作日相關配置
* @author chanson
* @return
*/
public WeekdayVO getWeekdayConfig(){
Map validateMap = new HashMap();
List weekendIsWeekdayList = new ArrayList();
List weekdayIsHolidayList = new ArrayList();
//1、放到web工程
File f = new File(getConfFile(BASE_PATH + "weekday.xml"));
//2、application測試
//String file = "D:/workspace/test/src/config/weekday.xml";
//File f = new File(file);
SAXReader reader = new SAXReader();
try{
Document doc = reader.read(f);
Element root = doc.getRootElement();
//===================================
//工作日校驗相關屬性
//===================================
Element validationElement = root.element("validation");
Element listElement;
for(Iterator i = validationElement.elementIterator("list");i.hasNext();){
listElement = (Element)i.next();
validateMap.put((String) listElement.elementText("key"),
(String)listElement.elementText("value"));
}
//===================================
//工作日是假期的列表
//===================================
Element weekdayElement = root.element("weekday");
Element holidayListElement = weekdayElement.element("holiday_list");
Element holidayValueElement = null;
for(Iterator i = holidayListElement.elementIterator("date");i.hasNext();){
holidayValueElement = (Element)i.next();
weekdayIsHolidayList.add((String)holidayValueElement.getText());
}
//===================================
//週末是工作日的列表
//===================================
Element weekendElement = root.element("weekend");
Element weekdayListElement = weekendElement.element("weekday_list");
Element weekdayValueElement = null;
for(Iterator i = weekdayListElement.elementIterator("date");i.hasNext();){
weekdayValueElement = (Element)i.next();
weekendIsWeekdayList.add((String)weekdayValueElement.getText());
}
WeekdayVO vo = new WeekdayVO();
vo.setValidateMap(validateMap);
vo.setWeekdayIsHolidayList(weekdayIsHolidayList);
vo.setWeekendIsWeekdayList(weekendIsWeekdayList);
return vo;
}catch(Exception e){
e.printStackTrace();
return null;
}
}
public static void main(String[] args) {
Dom4JUtil dom4JUtil = new Dom4JUtil();
WeekdayVO vo = dom4JUtil.getWeekdayConfig();
System.out.println(vo.getWeekdayIsHolidayList());
System.out.println(vo.getWeekendIsWeekdayList());
}
}
使用了一個POJO類:
- public class WeekdayVO {
- private Map validateMap;//工作日校驗
- private List weekendIsWeekdayList;//週末是工作日的列表
- private List weekdayIsHolidayList;//工作日是假期的列表
- //setter/getter(省略)
- }
public class WeekdayVO {
private Map validateMap;//工作日校驗
private List weekendIsWeekdayList;//週末是工作日的列表
private List weekdayIsHolidayList;//工作日是假期的列表
//setter/getter(省略)
}
3、修改WeekUtil類中的方法
1)、修改工作日判斷方法:
- public boolean isWeekday(GregorianCalendar calendar){
- Dom4JUtil dom4JUtil = new Dom4JUtil();
- WeekdayVO vo = dom4JUtil.getWeekdayConfig();
- SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
- if (calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SATURDAY
- && calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SUNDAY){
- //平時
- return !vo.getWeekdayIsHolidayList().contains(sdf.format(calendar.getTime()));
- }else{
- //週末
- return vo.getWeekendIsWeekdayList().contains(sdf.format(calendar.getTime()));
- }
- }
public boolean isWeekday(GregorianCalendar calendar){
Dom4JUtil dom4JUtil = new Dom4JUtil();
WeekdayVO vo = dom4JUtil.getWeekdayConfig();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
if (calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SATURDAY
&& calendar.get(GregorianCalendar.DAY_OF_WEEK) != GregorianCalendar.SUNDAY){
//平時
return !vo.getWeekdayIsHolidayList().contains(sdf.format(calendar.getTime()));
}else{
//週末
return vo.getWeekendIsWeekdayList().contains(sdf.format(calendar.getTime()));
}
}
2)、修改調用方式:
- public static void main(String[] args) {
- Dom4JUtil dom4JUtil = new Dom4JUtil();
- Map validateMap = dom4JUtil.getWeekdayConfig().getValidateMap();
- String EXCH_DATE_CHECK = (String)validateMap.get("EXCH_DATE_CHECK");
- WeekdayUtil dateUtils = new WeekdayUtil();
- boolean ok = dateUtils.compareWeekday("2009-10-1", "2009-10-15", Integer.parseInt(EXCH_DATE_CHECK));
- System.out.println("是否在五個工作日內:" + ok);
- }
public static void main(String[] args) {
Dom4JUtil dom4JUtil = new Dom4JUtil();
Map validateMap = dom4JUtil.getWeekdayConfig().getValidateMap();
String EXCH_DATE_CHECK = (String)validateMap.get("EXCH_DATE_CHECK");
WeekdayUtil dateUtils = new WeekdayUtil();
boolean ok = dateUtils.compareWeekday("2009-10-1", "2009-10-15", Integer.parseInt(EXCH_DATE_CHECK));
System.out.println("是否在五個工作日內:" + ok);
}
改造完畢。
更高級的改造
對於我現在的項目來說,算是完成了。當然還可以改得更好一些:
1、擴展XML,區分每年的工作日。(對於某些統計分析的項目,可能會用得着)
2、添加可視化頁面配置,避免了人工修改配置文件。
3、目前的XML文件中的日期格式有要求:
必須補全10位。例如:2008-1-1 必須配置成 2008-01-01。否則將匹配不上。