Java實現(xiàn)自動獲取法定節(jié)假日詳細代碼
一、背景
在實現(xiàn)業(yè)務需求的過程中,遇到了需要計算 x 個工作日后的日期需求。由于工作日是每年發(fā)布的,調(diào)休和休假都沒有規(guī)律,所以無法使用算法進行計算。
一般的實現(xiàn)方案是自己維護一個工作日和調(diào)休的表,或者去爬取發(fā)布的數(shù)據(jù)。但前者實現(xiàn)起來麻煩,每年都得搞一遍;后者可能涉及法律風險,爬蟲的識別策略也不太可靠。
所以還是考慮使用由專人維護的接口,找到了天行數(shù)據(jù)的接口,個人用戶有10個免費接口的額度,每個接口每天限制調(diào)用100次。
因為節(jié)假日一旦定下來就不會輕易改變,所以可以把獲取到的數(shù)據(jù)存在本地,這樣每天100次的接口額度完全夠用,不需要進行付費。
二、技術(shù)實現(xiàn)方案
整體流程:
- 讀取節(jié)假日配置:從本地文件中讀取節(jié)假日,如果本地沒有文件,則調(diào)用天行接口獲取。
- 解析數(shù)據(jù):從天行返回的數(shù)據(jù)里,獲取該年份里需要調(diào)休的日期和補班的日期。
- 計算日期:循環(huán)獲取日期,判斷是否為工作日,計算x個工作日后的日期。
實現(xiàn)細節(jié):
- 文件名:保存下來的文件,名字里要包含特定的年份。
- 計算邏輯:計算日期的時候,需要考慮到跨年的情況,跨年需要重新獲取下一年的數(shù)據(jù),再繼續(xù)進行計算日期。
- 日期判斷:工作日=不休假的周一至周五+補班的周六周末。
三、詳細代碼
Java 代碼
主要有五個類,HolidayResponse 是封裝天行API的返回結(jié)果;TianApiProperties 是獲取天行API的key;TianApiHolidayService 是接口;TianApiHolidayServiceImpl 里是具體實現(xiàn);HttpConnector 是接口請求,這個換成任何一個能發(fā)起http請求的庫都行。
目前代碼是基于SpringBoot寫的,但純粹只是為了方便,實際是可以轉(zhuǎn)成純Java工具代碼,不依賴于SpringBoot。
HolidayResponse.java
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import java.util.List;
/**
* @author jing
* @version 1.0
* @desc 返回結(jié)果
* @date 2023/12/19 11:40
**/
@Data
public class HolidayResponse {
@JsonProperty("code")
private int code; // 公共參數(shù) - 狀態(tài)碼
@JsonProperty("msg")
private String msg; // 公共參數(shù) - 錯誤信息
@JsonProperty("result")
private Result result; // 公共參數(shù) - 返回結(jié)果集
// Getters and setters
/**
* Represents the result section of the response.
*/
@Data
public static class Result {
@JsonProperty("update")
private boolean update; // 公共參數(shù) - 是否更新法定節(jié)假日
@JsonProperty("list")
private List<HolidayItem> list; // 應用參數(shù) - 節(jié)假日列表
// Getters and setters
}
/**
* Represents an item in the list of holidays.
*/
@Data
public static class HolidayItem {
@JsonProperty("holiday")
private String holiday; // 應用參數(shù) - 節(jié)日日期
@JsonProperty("name")
private String name; // 應用參數(shù) - 節(jié)假日名稱(中文)
@JsonProperty("vacation")
private String vacation; // 應用參數(shù) - 節(jié)假日數(shù)組
@JsonProperty("remark")
private String remark; // 應用參數(shù) - 調(diào)休日數(shù)組
@JsonProperty("wage")
private String wage; // 應用參數(shù) - 薪資法定倍數(shù)/按年查詢時為具體日期
@JsonProperty("start")
private int start; // 應用參數(shù) - 假期起點計數(shù)
@JsonProperty("now")
private int now; // 應用參數(shù) - 假期當前計數(shù)
@JsonProperty("end")
private int end; // 應用參數(shù) - 假期終點計數(shù)
@JsonProperty("tip")
private String tip; // 應用參數(shù) - 放假提示
@JsonProperty("rest")
private String rest; // 應用參數(shù) - 拼假建議
}
}TianApiProperties.java
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* @author jing
* @version 1.0
* @desc 配置
* @date 2023/12/19 11:25
**/
@Component
@Data
@ConfigurationProperties(prefix = "tianapi")
public class TianApiProperties {
/**
* 天行數(shù)據(jù)憑證key
*/
private String key;
}
TianApiHolidayService.java
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.time.LocalDateTime;
/**
* @author jing
* @version 1.0
* @desc 天行接口獲取節(jié)假日,目前使用的是免費接口,每天只能調(diào)用100次,后續(xù)如果需要調(diào)用更多次數(shù),可以考慮購買付費接口。只能獲取到今年和明年的節(jié)假日,明年的節(jié)假日需要在今年11月份左右才能獲取到
* @date 2023/12/19 11:25
**/
@Service
public interface TianApiHolidayService {
/**
* 計算x個工作日后的日期,跳過節(jié)假日
*
* @param startTime 開始日期
* @param workdaysToAdd 需要跳過的工作日天數(shù)
*/
LocalDateTime jumpWorkDay(LocalDateTime startTime, int workdaysToAdd) throws IOException;
}TianApiHolidayServiceImpl.java (核心邏輯)
import cn.hutool.core.date.DateUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.Gson;
import com.xxx.app.common.library.holiday.domain.HolidayResponse;
import com.xxx.app.common.library.holiday.properties.TianApiProperties;
import com.xxx.app.common.utils.http.HttpConnector;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author jing
* @version 1.0
* @desc 天行接口獲取節(jié)假日,目前使用的是免費接口,每天只能調(diào)用100次,后續(xù)如果需要調(diào)用更多次數(shù),可以考慮購買付費接口。只能獲取到今年和明年的節(jié)假日,明年的節(jié)假日需要在今年11月份左右才能獲取到
* @date 2023/12/19 11:25
**/
@Slf4j
@Service
public class TianApiHolidayServiceImpl implements TianApiHolidayService {
@Resource
private TianApiProperties tianApiProperties;
@Resource
private HttpConnector httpConnector;
private final String FILE_FORMAT = "./.holiday/%s_holiday.json";
/**
* 計算x個工作日后的日期,跳過節(jié)假日
*
* @param startTime 開始日期
* @param workdaysToAdd 需要跳過的工作日天數(shù)
*/
public LocalDateTime jumpWorkDay(LocalDateTime startTime, int workdaysToAdd) throws IOException {
// 從文件中讀取節(jié)假日
HolidayResponse response = getHolidayConfig(startTime);
if (response == null) {
return null;
}
// 節(jié)假日,只算周一到周五的
List<LocalDate> vacationList = new ArrayList<>();
// 補班列表,表示周末補班的
List<LocalDate> workDayList = new ArrayList<>();
extracted(response, vacationList, workDayList);
return workDayAdd(startTime, workdaysToAdd, vacationList, workDayList);
}
/**
* 提取返回數(shù)據(jù)里的節(jié)假日和調(diào)休列表
*
* @param response 返回數(shù)據(jù)
* @param vacationList 節(jié)假日列表
* @param workDayList 補班列表
*/
private static void extracted(HolidayResponse response, List<LocalDate> vacationList, List<LocalDate> workDayList) {
// 節(jié)假日列表
response.getResult().getList().forEach(item -> {
if (StringUtils.isNotEmpty(item.getWage())) {
String[] vList = item.getVacation().split("\\|");
for (String wage : vList) {
// 不需要上班的工作日
vacationList.add(LocalDate.parse(wage, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
}
if (StringUtils.isNotEmpty(item.getRemark())) {
String[] workList = item.getRemark().split("\\|");
for (String work : workList) {
// 需要上班的周末
workDayList.add(LocalDate.parse(work, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
}
}
});
}
/**
* 添加工作日
*
* @param startTime 開始時間
* @param workdaysToAdd 需要添加的工作日天數(shù)
* @param vacationList 節(jié)假日列表
* @param workDayList 補班列表
* @return LocalDateTime 返回添加工作日后的時間
* @throws IOException 異常
*/
private LocalDateTime workDayAdd(LocalDateTime startTime, int workdaysToAdd, List<LocalDate> vacationList, List<LocalDate> workDayList) throws IOException {
LocalDateTime result = startTime;
// 今年最后一天
LocalDateTime lastDayOfYear = LocalDateTime.of(LocalDate.of(startTime.getYear(), 12, 31), LocalTime.MAX);
// 循環(huán)計算,直到工作日天數(shù)為0,或者到了今年最后一天
while (workdaysToAdd > 0 && result.isBefore(lastDayOfYear)) {
// 判斷周一到周五,是否會放假,周六周日是否會補班
result = result.plusDays(1);
if (workDayNeedToWork(vacationList, result) && holidayNeedToWork(workDayList, result)) {
workdaysToAdd--;
}
}
// 如果還有剩余的工作日,就繼續(xù)往后推
if (workdaysToAdd > 0) {
// 如果還有剩余的工作日,就繼續(xù)往后推
return jumpWorkDay(result, workdaysToAdd);
}
return result;
}
/**
* 工作日需要去上班
*
* @param vacationList 節(jié)假日列表
* @param date 日期
* @return boolean 工作日是否需要上班
*/
private boolean workDayNeedToWork(List<LocalDate> vacationList, LocalDateTime date) {
DayOfWeek dayOfWeek = date.getDayOfWeek();
boolean isWork = dayOfWeek != DayOfWeek.SATURDAY && dayOfWeek != DayOfWeek.SUNDAY;
if (isWork) {
// 如果是工作日,還需要判斷是否會放假
LocalDate localDate = LocalDate.from(date);
return !vacationList.contains(localDate);
}
return true;
}
/**
* 周六末需要去補班
*
* @param workDayList 補班列表
* @param date 日期
* @return boolean 是否為休息日
*/
private boolean holidayNeedToWork(List<LocalDate> workDayList, LocalDateTime date) {
DayOfWeek dayOfWeek = date.getDayOfWeek();
boolean isHoliday = dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY;
if (isHoliday) {
// 如果是節(jié)假日,還需要判斷是否是補班
LocalDate localDate = LocalDate.from(date);
return workDayList.contains(localDate);
}
return true;
}
/**
* 獲取某個日期所在年份的節(jié)假日配置數(shù)據(jù),注:節(jié)假日指來自官方發(fā)布的有假節(jié)日,每年底政府公布后同步更新
*
* @param date 日期
* @return boolean
*/
public HolidayResponse getHolidayConfig(LocalDateTime date) throws IOException {
// 節(jié)假日文件路徑
String savePath = String.format(FILE_FORMAT, DateUtil.format(date, "yyyy"));
try {
// 從文件中讀取節(jié)假日
HolidayResponse response = readJsonFromFile(savePath);
if (response == null) {
String url = "https://apis.tianapi.com/jiejiari/index";
// 獲取當年的節(jié)假日列表
Map<String, String> params = new HashMap<>();
params.put("key", tianApiProperties.getKey());
params.put("date", DateUtil.format(date, "yyyy-MM-dd"));
params.put("type", "1");
String formData = httpConnector.fromData(params);
String rspBody = httpConnector.doFormPost(url, formData);
// 將json轉(zhuǎn)換為對象
Gson gson = new Gson();
response = gson.fromJson(rspBody, HolidayResponse.class);
// 將對象寫入文件
writeJsonToFile(response, savePath);
}
return response;
} catch (IOException e) {
log.error("Error during holiday configuration retrieval : {} , {}", savePath, e.getMessage());
}
return null;
}
/**
* 將json寫入文件
*
* @param jsonObject jsonObject
* @param filePath 文件路徑
*/
private void writeJsonToFile(HolidayResponse jsonObject, String filePath) {
try {
// Create directory if it doesn't exist
Path parentDirectory = FileSystems.getDefault().getPath(filePath).getParent();
if (parentDirectory != null && !Files.exists(parentDirectory)) {
Files.createDirectories(parentDirectory);
}
try (FileOutputStream fos = new FileOutputStream(filePath)) {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.writeValue(fos, jsonObject);
log.info("節(jié)假日文件寫入成功 : {} , {}", filePath, jsonObject);
} catch (Exception e) {
log.error("節(jié)假日文件寫入失敗 : {} , {}", filePath, e.getMessage());
}
} catch (IOException e) {
log.error("Error creating directory structure: {}", e.getMessage());
}
}
/**
* 從文件中讀取節(jié)假日
*
* @param filePath 文件路徑
* @return 節(jié)假日
*/
private HolidayResponse readJsonFromFile(String filePath) {
try {
// Create directory if it doesn't exist
Path parentDirectory = FileSystems.getDefault().getPath(filePath).getParent();
if (parentDirectory != null && !Files.exists(parentDirectory)) {
Files.createDirectories(parentDirectory);
}
try (FileInputStream fis = new FileInputStream(filePath)) {
ObjectMapper objectMapper = new ObjectMapper();
return objectMapper.readValue(fis, HolidayResponse.class);
} catch (Exception e) {
log.error("節(jié)假日文件讀取失敗 : {} , {}", filePath, e.getMessage());
}
} catch (IOException e) {
log.error("Error creating directory structure: {}", e.getMessage());
}
return null;
}
}HttpConnector.java (不重要,只是發(fā)起請求,可替換)
package com.xxx.app.common.utils.http;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.*;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.StringJoiner;
/**
* @author Jing
* @desc http 連接工具類
* https json post 請求用 doSSlPostRsp接口
*/
@Setter
@Slf4j
@Service
public class HttpConnector {
@Resource
private HttpClient httpClient;
/**
* 轉(zhuǎn)拼接參數(shù)
*
* @param url 接口地址
* @param params 參數(shù)
* @return 拼接后的參數(shù)
*/
public String addUrlParam(String url, Map<String, String> params) {
if (MapUtils.isNotEmpty(params)) {
StringBuilder sb = new StringBuilder(url);
sb.append("?");
for (String key : params.keySet()) {
sb.append(key).append("=").append(params.get(key)).append("&");
}
url = sb.substring(0, sb.length() - 1);
}
return url;
}
/**
* 發(fā)送帶參數(shù)post請求 表單請求頭
*
* @param url 接口地址
* @param postJson 傳參
* @return 響應數(shù)據(jù)
*/
public String doFormPost(String url, String postJson) throws IOException {
HttpPost httpPost = new HttpPost(url);
if (postJson != null) {
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setEntity(new StringEntity(postJson, Consts.UTF_8));
}
Map<String, String> headers = new HashMap<>();
return doRequest(headers, httpPost);
}
/**
* 發(fā)送帶參數(shù)post請求 表單請求頭
*
* @param url 接口地址
* @param formData 傳參
* @return 響應數(shù)據(jù)
*/
public String doFormPost(String url, Map<String, String> headers, String formData) throws IOException {
HttpPost httpPost = new HttpPost(url);
if (formData != null) {
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/x-www-form-urlencoded");
httpPost.setEntity(new StringEntity(formData, Consts.UTF_8));
}
return doRequest(headers, httpPost);
}
/**
* 發(fā)送帶文件和請求頭的post請求
*
* @param url 接口地址
* @param headers 請求頭
* @param file 文件
* @param fileName 文件名
* @return 響應數(shù)據(jù)
*/
public String doPost(String url, Map<String, String> headers, File file, String fileName) throws IOException {
HttpPost httpPost = new HttpPost(url);
if (file != null) {
httpPost.setEntity(assemblyFileEntity(file, fileName));
}
return doRequest(headers, httpPost);
}
/**
* 生成文件請求包
*
* @param file 文件
* @return http 請求體
*/
protected HttpEntity assemblyFileEntity(File file, String fileName) {
MultipartEntityBuilder build = MultipartEntityBuilder.create();
build.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
build.addBinaryBody("file", file);
build.addTextBody("filename", StringUtils.isBlank(fileName) ? file.getName() : fileName);
HttpEntity entity = build.build();
return entity;
}
/**
* 發(fā)送請求
*
* @param headers 請求頭
* @param httpRequest request
* @return 響應數(shù)據(jù)
*/
private String doRequest(Map<String, String> headers, HttpRequestBase httpRequest) throws IOException {
HttpRspBO rspBO = doRequestRsp(headers, httpRequest);
return rspBO.getBodyStr();
}
/**
* 發(fā)送request 請求
*
* @param headers
* @param httpRequest 注意這個方法需要自己關(guān)閉
* finally {
* httpRequest.releaseConnection();
* }
* @return 帶請求頭的響應數(shù)據(jù)封裝
*/
private HttpRspBO doRequestRsp(Map<String, String> headers, HttpRequestBase httpRequest) throws IOException {
if (headers != null) {
for (String key : headers.keySet()) {
httpRequest.addHeader(key, headers.get(key));
}
}
try {
HttpResponse response = httpClient.execute(httpRequest);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == HttpStatus.SC_OK) {
HttpRspBO bo = new HttpRspBO();
bo.setBodyStr(getEntity(response));
HashMap<String, String> map = new HashMap<>();
Header[] rspHeaders = response.getAllHeaders();
int i = 0;
while (i < rspHeaders.length) {
map.put(rspHeaders[i].getName(), rspHeaders[i].getValue());
i++;
}
bo.setHeaders(map);
return bo;
} else {
String entity = getEntity(response);
log.info("result msg " + entity);
throw new FinMgwException("");
}
} finally {
httpRequest.releaseConnection();
}
}
/**
* 解析返回請求體
*
* @param response 返回參數(shù)
* @return 字符串類型的請求體
*/
public String getEntity(HttpResponse response) throws IOException {
HttpEntity entity = response.getEntity();
if (entity == null) {
throw new FinMgwException(ResultCodeEnum.HTTP_EXECUTE_EX.getCode(),
ResultCodeEnum.HTTP_EXECUTE_EX.getDesc() + ", http response entity is null.");
}
String result;
// 去掉首尾的 ""
result = EntityUtils.toString(entity, Consts.UTF_8);
String delStr = "\"";
if (result.indexOf(delStr) == 0) {
result = result.substring(1);
}
if (result.lastIndexOf(delStr) == result.length() - 1) {
result = result.substring(0, result.length() - 1);
}
return result;
}
/**
* 將參數(shù)轉(zhuǎn)換為form data傳參
*
* @param param map集合
* @return form data
*/
public String fromData(Map<String, String> param) {
StringJoiner joiner = new StringJoiner("&");
for (Map.Entry<String, String> map : param.entrySet()) {
String data = String.format("%s=%s", map.getKey(), map.getValue());
joiner.add(data);
}
return joiner.toString();
}
}使用示例:
application.yml 配置
# 天行api tianapi: # API密鑰 key: xxxxxxxxxxxxxxxxxxxxxxxxxxx
demo 代碼:
@Slf4j
@Service
public class Demo {
@Resource
private TianApiHolidayService tianApiHolidayService;
public void get(){
LocalDateTime publishTime = LocalDateTime.now()
// 計算五個工作日后的日期
LocalDateTime deadlineTime = tianApiHolidayService.jumpWorkDay(publishTime, 5);
}
}理論上可以擴展很多方法,比如判斷當前是否工作日/節(jié)假日,減去x個工作日之類的。但不太想寫了,暫時用不著。
四、相關(guān)依賴
天行API申請:
節(jié)假日API接口 - 天行數(shù)據(jù)TianAPI
代碼依賴:
Java 版本 = 1.8
Maven 版本 = 3.9.2
涉及maven依賴版本:
<!--SpringBoot 啟動插件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<version>2.3.4.RELEASE</version>
<exclusions>
<exclusion>
<artifactId>log4j-api</artifactId>
<groupId>org.apache.logging.log4j</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.3.4.RELEASE<</version>
</dependency>
<!--簡化開發(fā)的jar 包-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
<version>1.18.16</version>
</dependency>
<!--日期轉(zhuǎn)化-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.10</version>
</dependency>
<!--json解析-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.10.2</version>
</dependency>
<!--json解析-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.9</version>
</dependency>五、補充
附帶上2024年的節(jié)假日數(shù)據(jù),如果只是要判斷2024年的,那直接把文件放在項目目錄/.holiday 目錄下即可,不需要再申請?zhí)煨械腁PI接口權(quán)限。
或者拿這個去調(diào)試代碼也可以,但需要保證日期范圍在2024年內(nèi),否則會自動調(diào)用天行API接口獲取其他年份的數(shù)據(jù)。
文件名:2024_holiday.json
{
"code": 200,
"msg": "success",
"result": {
"update": true,
"list": [
{
"holiday": "1月1號",
"name": "元旦節(jié)",
"vacation": "2023-12-30|2023-12-31|2024-01-01",
"remark": "",
"wage": "2024-01-01",
"start": 0,
"now": 0,
"end": 2,
"tip": "1月1日放假,與周末連休,共三天。",
"rest": "2023年12月28日至12月29日請假2天,與周末連休可拼5天小長假。"
},
{
"holiday": "2月10號",
"name": "春節(jié)",
"vacation": "2024-02-10|2024-02-11|2024-02-12|2024-02-13|2024-02-14|2024-02-15|2024-02-16|2024-02-17",
"remark": "2024-02-04|2024-02-18",
"wage": "2024-02-10|2024-02-11|2024-02-12",
"start": 0,
"now": 0,
"end": 7,
"tip": "2月10日至17日放假調(diào)休,共8天。2月4日(星期日)、2月18日(星期日)上班。鼓勵各單位結(jié)合帶薪年休假等制度落實,安排職工在除夕(2月9日)休息。",
"rest": "2月8日至2月9日請假2天,與春節(jié)連休可拼10天長假。"
},
{
"holiday": "4月4號",
"name": "清明節(jié)",
"vacation": "2024-04-04|2024-04-05|2024-04-06",
"remark": "2024-04-07",
"wage": "2024-04-04",
"start": 0,
"now": 0,
"end": 2,
"tip": "4月4日至6日放假調(diào)休,共3天。4月7日(星期日)上班。",
"rest": "4月3日和4月7日請假2天,與清明節(jié)連休可拼5天小長假。"
},
{
"holiday": "5月1號",
"name": "勞動節(jié)",
"vacation": "2024-05-01|2024-05-02|2024-05-03|2024-05-04|2024-05-05",
"remark": "2024-04-28|2024-05-11",
"wage": "2024-05-01",
"start": 0,
"now": 0,
"end": 4,
"tip": "5月1日至5日放假調(diào)休,共5天。4月28日(星期日)、5月11日(星期六)上班。",
"rest": "4月28日至4月30日請假3天,周六與勞動節(jié)連休可拼9天長假。"
},
{
"holiday": "6月10號",
"name": "端午節(jié)",
"vacation": "2024-06-08|2024-06-09|2024-06-10",
"remark": "",
"wage": "2024-06-10",
"start": 0,
"now": 0,
"end": 2,
"tip": "6月10日放假,與周末連休,共3天。",
"rest": "6月6日至6月7日請假2天,與端午節(jié)連休可拼5天小長假。"
},
{
"holiday": "9月15號",
"name": "中秋節(jié)",
"vacation": "2024-09-15|2024-09-16|2024-09-17",
"remark": "2024-09-14",
"wage": "2024-09-17",
"start": 0,
"now": 0,
"end": 2,
"tip": "9月15日至17日放假調(diào)休,共3天。9月14日(星期六)上班。",
"rest": "9月13日至9月14日請假2天,與周日連休可拼5天小長假。"
},
{
"holiday": "10月1號",
"name": "國慶節(jié)",
"vacation": "2024-10-01|2024-10-02|2024-10-03|2024-10-04|2024-10-05|2024-10-06|2024-10-07",
"remark": "2024-09-29|2024-10-12",
"wage": "2024-10-01|2024-10-02|2024-10-03",
"start": 0,
"now": 0,
"end": 6,
"tip": "10月1日至7日放假調(diào)休,共7天。9月29日(星期日)、10月12日(星期六)上班。",
"rest": "9月29日至9月30號請假2天,周六與國慶節(jié)連休可拼10天長假。"
}
]
}
}總結(jié)
到此這篇關(guān)于Java實現(xiàn)自動獲取法定節(jié)假日的文章就介紹到這了,更多相關(guān)Java自動獲取法定節(jié)假內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
JDK1.8中ConcurrentHashMap中computeIfAbsent死循環(huán)bug問題
這篇文章主要介紹了JDK1.8中ConcurrentHashMap中computeIfAbsent死循環(huán)bug,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
SpringBoot 改造成https訪問的實現(xiàn)
這篇文章主要介紹了SpringBoot 改造成https訪問的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-10-10
Springboot+redis+Interceptor+自定義annotation實現(xiàn)接口自動冪等
本篇文章給大家介紹了使用springboot和攔截器、redis來優(yōu)雅的實現(xiàn)接口冪等,對于冪等在實際的開發(fā)過程中是十分重要的,因為一個接口可能會被無數(shù)的客戶端調(diào)用,如何保證其不影響后臺的業(yè)務處理,如何保證其只影響數(shù)據(jù)一次是非常重要的,感興趣的朋友跟隨小編一起看看吧2019-07-07
maven插件assembly使用及springboot啟動腳本start.sh和停止腳本 stop.sh
這篇文章主要介紹了maven插件assembly使用及springboot啟動腳本start.sh和停止腳本 stop.sh的相關(guān)資料,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-08-08
Spring Boot集成tablesaw插件快速入門示例代碼
Tablesaw是一款Java的數(shù)據(jù)可視化庫,數(shù)據(jù)解析庫,主要用于加載數(shù)據(jù),對數(shù)據(jù)進行操作(轉(zhuǎn)化,過濾,匯總等),類比Python中的Pandas庫,本文介紹Spring Boot集成tablesaw插件快速入門Demo,感興趣的朋友一起看看吧2024-06-06
Spring自定義注解實現(xiàn)數(shù)據(jù)脫敏
在當今數(shù)據(jù)安全越來越受到重視的背景下,許多企業(yè)都對敏感數(shù)據(jù)的保護有著嚴格的要求,本文就來深入探討一下如何自定義注解來實現(xiàn)對敏感數(shù)據(jù)的脫敏處理吧2024-11-11

