基于Java代碼實(shí)現(xiàn)判斷春節(jié)、端午節(jié)、中秋節(jié)等法定節(jié)假日的方法
一、前言
最近工作上遇到一個(gè)問(wèn)題,后端有一個(gè)定時(shí)任務(wù),需要用JAVA每天判斷法定節(jié)假日、周末放假,上班等情況,其實(shí)想單獨(dú)通過(guò)邏輯什么的去判斷中國(guó)法定節(jié)假日的放假情況,基本不可能,因?yàn)閲?guó)家每一年的假期可能不一樣,是人為設(shè)定的;
所以只能依靠其它手段,能想到的比較靠譜的如下:
1.網(wǎng)絡(luò)接口:有些數(shù)據(jù)服務(wù)商會(huì)提供,要么是收錢(qián)的,要么是次數(shù)限制,等等各種問(wèn)題,效果不理想,可控性差,我也沒(méi)試過(guò),如:
https://www.juhe.cn/docs/api/id/177/aid/601
或者
http://apistore.baidu.com/apiworks/servicedetail/1116.html
2.在線解析網(wǎng)頁(yè)信息,獲取節(jié)假日情況:嚴(yán)重依賴(lài)被解析的網(wǎng)站網(wǎng)頁(yè),所以在選取網(wǎng)站的時(shí)候,要找稍微靠譜點(diǎn)的;
3.根據(jù)國(guó)家規(guī)定的法定節(jié)假日放假情況,每年錄入系統(tǒng),這種如果客戶(hù)不怕麻煩的話(huà)。還是比較靠譜的;
本Demo將選擇第二種來(lái)實(shí)現(xiàn);
二、使用htmlunit在線解析網(wǎng)頁(yè)信息,獲取節(jié)假日情況
一開(kāi)始是使用jsoup去解析網(wǎng)頁(yè)的,效果不理想,如果網(wǎng)頁(yè)是動(dòng)態(tài)生成的時(shí)候,用jsoup遇到了各種問(wèn)題,所以改成了htmlunit,總得來(lái)說(shuō)htmlunit還是很強(qiáng)大的,能夠模擬瀏覽器運(yùn)行,被譽(yù)為java瀏覽器的開(kāi)源實(shí)現(xiàn);
首先去官網(wǎng)下載相關(guān)jar包,以及閱讀相關(guān)文檔:
http://htmlunit.sourceforge.net/
我這里解析的網(wǎng)頁(yè)是360的萬(wàn)年歷:
日歷界面如下:
被解析的 HTML格式如下:
實(shí)現(xiàn)步驟:
1、加載頁(yè)面;
2、循環(huán)等待頁(yè)面加載完成(可能會(huì)有一些動(dòng)態(tài)頁(yè)面,是用javascript生成);
3、根據(jù)網(wǎng)頁(yè)格式解析html內(nèi)容,并提取關(guān)鍵信息存入封裝好的對(duì)象;
注意點(diǎn):
1、難點(diǎn)在于判斷是否休假及假期類(lèi)型,由于原頁(yè)面并沒(méi)有標(biāo)明每一天的假期類(lèi)型,所以這里的邏輯要自己去實(shí)現(xiàn),詳情參考代碼;
2、之所以有個(gè)靜態(tài)latestVocationName變量,是防止出現(xiàn)以下情況(出現(xiàn)該情況的概率極低;PS:方法要每天調(diào)用一次,該變量才生效):
代碼實(shí)現(xiàn):
定義一個(gè)中國(guó)日期類(lèi):
package com.pichen.tools.getDate; import java.util.Date; public class ChinaDate { /** * 公歷時(shí)間 */ private Date solarDate; /** * 農(nóng)歷日 */ private String lunar; /** * 公歷日 */ private String solar; /** * 是否是 休 */ private boolean isVacation = false; /** * 如果是 休情況下的假期名字 */ private String VacationName = "非假期"; /** * 是否是 班 */ private boolean isWorkFlag = false; private boolean isSaturday = false; private boolean isSunday = false; /** * @return the solarDate */ public Date getSolarDate() { return solarDate; } /** * @param solarDate the solarDate to set */ public void setSolarDate(Date solarDate) { this.solarDate = solarDate; } /** * @return the lunar */ public String getLunar() { return lunar; } /** * @param lunar the lunar to set */ public void setLunar(String lunar) { this.lunar = lunar; } /** * @return the solar */ public String getSolar() { return solar; } /** * @param solar the solar to set */ public void setSolar(String solar) { this.solar = solar; } /** * @return the isVacation */ public boolean isVacation() { return isVacation; } /** * @param isVacation the isVacation to set */ public void setVacation(boolean isVacation) { this.isVacation = isVacation; } /** * @return the vacationName */ public String getVacationName() { return VacationName; } /** * @param vacationName the vacationName to set */ public void setVacationName(String vacationName) { VacationName = vacationName; } /** * @return the isWorkFlag */ public boolean isWorkFlag() { return isWorkFlag; } /** * @param isWorkFlag the isWorkFlag to set */ public void setWorkFlag(boolean isWorkFlag) { this.isWorkFlag = isWorkFlag; } /** * @return the isSaturday */ public boolean isSaturday() { return isSaturday; } /** * @param isSaturday the isSaturday to set */ public void setSaturday(boolean isSaturday) { this.isSaturday = isSaturday; } /** * @return the isSunday */ public boolean isSunday() { return isSunday; } /** * @param isSunday the isSunday to set */ public void setSunday(boolean isSunday) { this.isSunday = isSunday; } }
解析網(wǎng)頁(yè),并調(diào)用demo,打印本月詳情,和當(dāng)天詳情:
package com.pichen.tools.getDate; import java.io.IOException; import java.net.MalformedURLException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.List; import com.gargoylesoftware.htmlunit.FailingHttpStatusCodeException; import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.DomNodeList; import com.gargoylesoftware.htmlunit.html.HtmlElement; import com.gargoylesoftware.htmlunit.html.HtmlPage; public class Main { private static String latestVocationName=""; public String getVocationName(DomNodeList<HtmlElement> htmlElements, String date) throws ParseException{ String rst = ""; boolean pastTimeFlag = false; DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); Date paramDate = dateFormat.parse(date); if(new Date().getTime() >= paramDate.getTime()){ pastTimeFlag = true; } //first step //jugde if can get vocation name from html page for(int i = 0; i < htmlElements.size(); i++){ HtmlElement element = htmlElements.get(i); if(element.getAttribute("class").indexOf("vacation")!=-1){ boolean hitFlag = false; String voationName = ""; for(; i < htmlElements.size(); i++){ HtmlElement elementTmp = htmlElements.get(i); String liDate = elementTmp.getAttribute("date"); List<HtmlElement> lunar = elementTmp.getElementsByAttribute("span", "class", "lunar"); String lanarText = lunar.get(0).asText(); if(lanarText.equals("元旦")){ voationName = "元旦"; }else if(lanarText.equals("除夕")||lanarText.equals("春節(jié)")){ voationName = "春節(jié)"; }else if(lanarText.equals("清明")){ voationName = "清明"; }else if(lanarText.equals("國(guó)際勞動(dòng)節(jié)")){ voationName = "國(guó)際勞動(dòng)節(jié)"; }else if(lanarText.equals("端午節(jié)")){ voationName = "端午節(jié)"; }else if(lanarText.equals("中秋節(jié)")){ voationName = "中秋節(jié)"; }else if(lanarText.equals("國(guó)慶節(jié)")){ voationName = "國(guó)慶節(jié)"; } if(liDate.equals(date)){ hitFlag = true; } if(elementTmp.getAttribute("class").indexOf("vacation")==-1){ break; } } if(hitFlag == true && !voationName.equals("")){ rst = voationName; break; } }else{ continue; } } //if first step fail(rarely), get from the latest Vocation name if(rst.equals("")){ System.out.println("warning: fail to get vocation name from html page."); //you can judge by some simple rule //from the latest Vocation name rst = Main.latestVocationName; }else if(pastTimeFlag == true){ //更新《當(dāng)前時(shí)間,且最近一次的可見(jiàn)的假期名 Main.latestVocationName = rst; } return rst; } public List<ChinaDate> getCurrentDateInfo(){ WebClient webClient = null; List<ChinaDate> dateList = null; try{ DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); dateList = new ArrayList<ChinaDate>(); webClient = new WebClient(); HtmlPage page = webClient.getPage("http://hao.#/rili/"); //最大等待60秒 for(int k = 0; k < 60; k++){ if(!page.getElementById("M-dates").asText().equals("")) break; Thread.sleep(1000); } //睡了8秒,等待頁(yè)面加載完成...,有時(shí)候,頁(yè)面可能獲取不到,不穩(wěn)定() //Thread.sleep(8000); DomNodeList<HtmlElement> htmlElements = page.getElementById("M-dates").getElementsByTagName("li"); //System.out.println(htmlElements.size()); for(HtmlElement element : htmlElements){ ChinaDate chinaDate = new ChinaDate(); List<HtmlElement> lunar = element.getElementsByAttribute("span", "class", "lunar"); List<HtmlElement> solar = element.getElementsByAttribute("div", "class", "solar"); chinaDate.setLunar(lunar.get(0).asText()); chinaDate.setSolar(solar.get(0).asText()); chinaDate.setSolarDate(dateFormat.parse(element.getAttribute("date"))); if(element.getAttribute("class").indexOf("vacation")!=-1){ chinaDate.setVacation(true); chinaDate.setVacationName(this.getVocationName(htmlElements, element.getAttribute("date"))); } if(element.getAttribute("class").indexOf("weekend")!=-1 && element.getAttribute("class").indexOf("last")==-1){ chinaDate.setSaturday(true); } if(element.getAttribute("class").indexOf("last weekend")!=-1){ chinaDate.setSunday(true); } if(element.getAttribute("class").indexOf("work")!=-1){ chinaDate.setWorkFlag(true); }else if(chinaDate.isSaturday() == false && chinaDate.isSunday() == false && chinaDate.isVacation() == false ){ chinaDate.setWorkFlag(true); }else{ chinaDate.setWorkFlag(false); } dateList.add(chinaDate); } }catch(Exception e){ e.printStackTrace(); System.out.println("get date from http://hao.#/rili/ error~"); }finally{ webClient.close(); } return dateList; } public ChinaDate getTodayInfo(){ List<ChinaDate> dateList = this.getCurrentDateInfo(); DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); for(ChinaDate date: dateList){ if(dateFormat.format(date.getSolarDate()).equals(dateFormat.format(new Date()))){ return date; } } return new ChinaDate(); } public static void main(String[] args) throws FailingHttpStatusCodeException, MalformedURLException, IOException, InterruptedException { List<ChinaDate> dateList = new Main().getCurrentDateInfo(); ChinaDate today = new Main().getTodayInfo(); DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd"); System.out.println("本月詳情:"); for(ChinaDate date: dateList){ System.out.println(dateFormat.format(date.getSolarDate()) + " " + date.getVacationName()); } System.out.println("------------------------------------------------------------------------"); System.out.println("今日詳情:"); System.out.println("日期:" + today.getSolarDate()); System.out.println("農(nóng)歷:"+today.getLunar()); System.out.println("公歷:"+today.getSolar()); System.out.println("假期名:"+today.getVacationName()); System.out.println("是否周六:"+today.isSaturday()); System.out.println("是否周日:"+today.isSunday()); System.out.println("是否休假:"+today.isVacation()); System.out.println("是否工作日:"+today.isWorkFlag()); System.out.println("已發(fā)生的最近一次假期:" + Main.latestVocationName); } }
運(yùn)行程序,結(jié)果正確:
相關(guān)文章
IDEA自動(dòng)生成TestNG的testng.xml的插件方法
這篇文章主要介紹了IDEA自動(dòng)生成TestNG的testng.xml的插件方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-04-04Springboot JPA 枚舉Enum類(lèi)型存入到數(shù)據(jù)庫(kù)的操作
這篇文章主要介紹了Springboot JPA 枚舉Enum類(lèi)型存入到數(shù)據(jù)庫(kù)的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2021-01-01mysql數(shù)據(jù)庫(kù)忘記密碼時(shí)如何修改
本文主要介紹了mysql數(shù)據(jù)庫(kù)忘記密碼時(shí)如何修改的步驟方法,具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧2017-02-02SpringBoot實(shí)現(xiàn)讀取YML,yaml,properties文件
yml,yaml,properties三種文件都是用來(lái)存放配置的文件,一些靜態(tài)數(shù)據(jù),配置的數(shù)據(jù)都會(huì)存放到里邊。本文主要為大家整理了SpringBoot實(shí)現(xiàn)讀取YML,yaml,properties文件的方法,需要的可以參考一下2023-04-04java實(shí)現(xiàn)計(jì)算器加法小程序(圖形化界面)
這篇文章主要介紹了Java實(shí)現(xiàn)圖形化界面的計(jì)算器加法小程序,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-05-05IntelliJ IDEA JRebel 安裝使用圖文教程(熱部署插件)
IDEA 全稱(chēng) IntelliJ IDEA,是java語(yǔ)言開(kāi)發(fā)的集成環(huán)境,IntelliJ在業(yè)界被公認(rèn)為最好的java開(kāi)發(fā)工具之一。這篇文章主要介紹了IntelliJ IDEA 熱部署插件JRebel 安裝使用圖文教程,需要的朋友可以參考下2018-03-03SpringCloud Zuul實(shí)現(xiàn)動(dòng)態(tài)路由
這篇文章主要介紹了SpringCloud Zuul實(shí)現(xiàn)動(dòng)態(tài)路由,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-01-01