java获取国家法定节假日(不依赖API)

java获取国家法定节假日, 由此可获取每月第一个工作日和最后一个工作日

(不依赖API,主要是因为API接口不可靠或计费,此工具依赖国务院发布的节假日基础信息进行解析)

本工具仅供参考学习。各类数据获取需遵守法律法规

package com.exrate;

import cn.hutool.core.util.NumberUtil;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

import java.io.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.ConcurrentSkipListSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author Q
 */
public class ChinaHolidaysUtils {
    /**
     * 国务院发布的节假日安排的通知 保存的文件路径
     */
    private static final String HOLIDAY_NOTICES_FILE_PATH = ChinaHolidaysUtils.class.getResource("/").getPath()+"国务院发布的节假日安排的通知/";
    /**
     * 国务院文件搜索地址
     */
    private static final String GOV_URL = "http://sousuo.gov.cn/s.htm?t=paper&advance=false&n=10&timetype=timeqb&mintime=&maxtime=&sort=pubtime&q=%E8%8A%82%E5%81%87%E6%97%A5%E5%AE%89%E6%8E%92%E7%9A%84%E9%80%9A%E7%9F%A5";

    private static Set<String> publicHolidays = new ConcurrentSkipListSet<>();
    private static Set<String> oxenHorseDays = new ConcurrentSkipListSet<>();

    public static void main(String[] args) {
        try {
            System.out.println(isOxenHorseDays(LocalDate.now().toString()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        System.out.println("publicHolidays: " + publicHolidays);
        System.out.println("oxenHorseDays: " + oxenHorseDays);
    }

    /**
     * 是否为调休补班日
     * @param localDate
     * @return
     * @throws IOException
     */
    public static boolean isOxenHorseDays(String localDate) throws IOException {
        if(oxenHorseDays.isEmpty()){
            getDays(localDate, publicHolidays, oxenHorseDays);
        }
        return oxenHorseDays.contains(localDate);
    }

    /**
     * 是否为法定节假日
     * @param localDate
     * @return
     * @throws IOException
     */
    public static boolean isPublicHolidays(String localDate) throws IOException {
        if(publicHolidays.isEmpty()){
            getDays(localDate, publicHolidays, oxenHorseDays);
        }
        return publicHolidays.contains(localDate);
    }

    private static synchronized void getDays(String localDate, Set<String> publicHolidays, Set<String> oxenHorseDays) throws IOException {
        //获取xxx年的节假日数据
        String year = null;
        if(StringUtils.isEmpty(localDate)){
            year = String.valueOf(LocalDate.parse(localDate).getYear());
        }else{
            year = String.valueOf(LocalDate.now().getYear());
        }
        //先通过缓存文件,否则使用http获取
        String html = getHtmlByCacheFiles(year);
        if(html == null){
            html = getHtmlByHttp(year);
        }
        Document doc = Jsoup.parse(html);
        Element content = doc.select("div.b12c.pages_content").first();
        Elements paragraphs = content.select("p");
        for (Element p : paragraphs) {
            String text = p.text();
            if (text.contains("、") && text.contains(":") && text.contains("。") && text.contains("放假")) {
                text = text.substring(text.indexOf(":")+1);
                String[] sentences = text.split("。");
                for (String sentence : sentences) {
                    if (sentence.contains("放假")) {
                        String t = sentence.split("放假")[0];
                        if (t.contains("至")) {
                            String start = t.split("至")[0];
                            String startDay=null, startMonth=null, startYear=null;
                            if(start.contains("日") || start.contains("月") || start.contains("年")){
                                startDay = getDigit(start, "日");
                                startMonth = getDigit(start, "月");
                                startYear = getDigit(start, "年");
                            }
                            LocalDate startDate = parseDate(startYear==null?year:startYear, startMonth, startDay);
                            String end = t.split("至")[1];
                            String endDay=null, endMonth=null, endYear=null;
                            if(end.contains("日") || end.contains("月") || end.contains("年")){
                                endDay = getDigit(end, "日");
                                endMonth = getDigit(end, "月");
                                endYear = getDigit(end, "年");
                            }
                            LocalDate endDate = parseDate(endYear==null?(startYear==null?year:startYear):endYear, endMonth==null?startMonth:endMonth, endDay);
                            for (LocalDate date = startDate; !date.isAfter(endDate); date = date.plusDays(1)) {
                                publicHolidays.add(date.toString());
                            }
                        } else {
                            String tDay=null, tMonth=null, tYear=null;
                            if(t.contains("日") || t.contains("月") || t.contains("年")){
                                tDay = getDigit(t, "日");
                                tMonth = getDigit(t, "月");
                                tYear = getDigit(t, "年");
                            }
                            LocalDate date = parseDate(tYear==null? year:tYear, tMonth, tDay);
                            publicHolidays.add(date.toString());
                        }
                    }
                    if (sentence.contains("上班")) {
                        String t = sentence.split("上班")[0];
                        if (sentence.contains("、")) {
                            String[] dates = sentence.split("、");
                            for (String dateStr : dates) {
                                String tDay=null, tMonth=null, tYear=null;
                                if(dateStr.contains("日") || dateStr.contains("月") || dateStr.contains("年")){
                                    tDay = getDigit(dateStr, "日");
                                    tMonth = getDigit(dateStr, "月");
                                    tYear = getDigit(dateStr, "年");
                                }
                                LocalDate date = parseDate(tYear==null? year:tYear, tMonth, tDay);
                                oxenHorseDays.add(date.toString());
                            }
                        }else{
                            String tDay=null, tMonth=null, tYear=null;
                            if(t.contains("日") || t.contains("月") || t.contains("年")){
                                tDay = getDigit(t, "日");
                                tMonth = getDigit(t, "月");
                                tYear = getDigit(t, "年");
                            }
                            LocalDate date = parseDate(tYear==null? year:tYear, tMonth, tDay);
                            oxenHorseDays.add(date.toString());
                        }
                    }
                }
            }
        }
    }

    /**
     * 模拟人为操作的参数
     * @param url
     */
    private static Request getRequestSetUnifiedHead(String url){
        Request.Builder builder = new Request.Builder();
        builder.header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36")
               .header("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
               .header("Host", "www.gov.cn")
               .header("Referer", "http://sousuo.gov.cn/")
//             .header("Accept-Encoding", "gzip, deflate, br") 造成乱码问题
               .header("Accept-Language", "zh-CN,zh;q=0.9")
               .header("Cache-Control", "max-age=0")
               .header("Connection", "keep-alive")
               .header("Sec-Fetch-Dest", "document")
               .header("Sec-Fetch-Mode", "navigate")
               .header("Sec-Fetch-Site", "cross-site")
               .header("Sec-Fetch-User", "?1")
               .header("Upgrade-Insecure-Requests", "1")
               .header("sec-ch-ua", "\"Not.A/Brand\";v=\"8\", \"Chromium\";v=\"114\", \"Google Chrome\";v=\"114\"")
               .header("sec-ch-ua-mobile", "?0")
               .header("sec-ch-ua-platform", "Windows");
        return builder.url(url).build();
    }

    /**
     * http get请求
     * @param client
     * @param url
     * @return
     * @throws IOException
     */
    private static String httpGet(OkHttpClient client, String url) throws IOException {
        Request request = getRequestSetUnifiedHead(url);
        Response response = client.newCall(request).execute();
        if (!response.isSuccessful()) {
            throw new IOException("获取数据失败:" + url);
        }
        String html = response.body().string();
        System.out.println("进行了一次http get请求:" + url);
        return html;
    }
    /**
     * 通过http获取国务院发布xxxx年的节假日安排的通知
     * @return
     * @throws IOException
     */
    private static String getHtmlByHttp(String year) throws IOException {
        OkHttpClient client = new OkHttpClient();
        String html = httpGet(client, GOV_URL);
        Document doc = Jsoup.parse(html);
        Elements resList = doc.select("li.res-list");
        if (!resList.isEmpty()) {
            Optional<Element> optional = resList.stream().filter(res -> res.text().contains("国务院办公厅关于"+year+"年")).findFirst();
            if (!optional.isPresent()) {
                throw new IOException("未获取到"+ year +"年节假日安排的通知:" + GOV_URL);
            }
            Element element = optional.get();
            String linkUrl = element.select("a[href]").attr("abs:href");
            html = httpGet(client, linkUrl);
            str2File(html, HOLIDAY_NOTICES_FILE_PATH, year+"节假日安排的通知-源数据", ".html");
            Document resDoc = Jsoup.parse(html);
            str2File(html, HOLIDAY_NOTICES_FILE_PATH, resDoc.title(), ".html");
            return html;
        }
        return null;
    }

    /**
     * 先通过缓存节假日通知的指定目录中获取 当年的 节假日通知文件
     * @param year
     * @return
     */
    private static String getHtmlByCacheFiles(String year) {
        String[] paths = new File(HOLIDAY_NOTICES_FILE_PATH).list();
        if(paths != null && paths.length > 0){
            Optional<String> yearPath = Arrays.stream(paths).filter(p -> p.contains(year)).findFirst();
            if (yearPath.isPresent()){
                return file2Str(HOLIDAY_NOTICES_FILE_PATH + yearPath.get());
            }
        }
        return null;
    }


    /**
     * 根据年月日字符转为 yyyy-M-d 格式的LocalDate
     * @param year
     * @param month
     * @param day
     * @return
     */
    private static LocalDate parseDate(String year, String month, String day) {
        String dateStr = year + "-" + month + "-" + day;
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-M-d");
        return LocalDate.parse(dateStr, formatter);
    }

    /**
     * 将字符串内容转为文件存到指定路径下
     * @param str
     * @param filePath
     */
    public static void str2File(String str, String filePath, String fileName, String fileSuffix) throws IOException {
        File file = new File(filePath + fileName + fileSuffix);
        if (!file.getParentFile().exists()) {
            boolean created = file.getParentFile().mkdirs();
            if (!created) {
                throw new IOException("文件路径创建失败");
            }
        }
        try (FileWriter writer = new FileWriter(file)) {
            writer.write(str);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 将指定路径的文件转为字符串
     * @param filePath
     * @return
     */
    private static String file2Str(String filePath) {
        File file = new File(filePath);
        try (FileReader reader = new FileReader(file)) {
            char[] buffer = new char[(int) file.length()];
            reader.read(buffer);
            return new String(buffer);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取指定字符串前的数字
     */
    private static final Pattern PATTERN = Pattern.compile("[^\\d]");
    private static String getDigit(String content, String targetStr) {
        if(!content.contains(targetStr)){
            return null;
        }
        content = content.substring(0, content.indexOf(targetStr));
        StringBuffer sb = new StringBuffer(content);
        content = sb.reverse().toString();
        //使用正则表达式匹配第一个非数字
        Matcher matcher = PATTERN.matcher(content);
        if (matcher.find()) {
            content = content.substring(0, matcher.start());
            sb = new StringBuffer(content);
            return sb.reverse().toString();
        }
        //是否为数字
        if(NumberUtil.isNumber(content)){
            return new StringBuffer(content).reverse().toString();
        }
        return null;
    }


}

### AI智能客服与智能会话 #### 定义与概念 AI智能客服指的是利用人工智能技术实现客户服务自动化的一种解决方案。这类系统可以理解并回应用户的查询,提供帮助和服务支持。其核心在于模拟人类对话过程中的交互行为,使得机器能够以自然的方式同客户交流。 #### 工作原理 智能客服的工作机制依赖于多种先进技术的支持: - **自然语言处理(NLP)**:这是指让计算机理解和生成人类使用的文字或语音的能力。通过对输入的信息进行语义分析、意图识别以及上下文管理等操作,智能客服得以解析用户的需求并向用户提供恰当的回答[^3]。 - **机器学习算法**:为了提高响应质量,智能客服还会采用监督式学习方法训练模型,使其可以从大量历史案例中学习最佳实践;同时也会运用强化学习断优化自身的策略,在实际应用场景里做出更加合理的判断和建议[^1]。 - **知识库集成**:除了依靠内置逻辑外,很多先进的智能客服还连接着庞大的后台数据库作为支撑。当遇到复杂问题时,它们可以通过检索这些结构化信息源获取准确答案,并将其转化为易于被顾客接受的形式呈现出来。 #### 主要应用领域 随着技术进步,越来越多的企业开始部署AI驱动的聊天机器人来改善用户体验、降低运营成本并增强竞争力。以下是几个典型的应用场景: - **电子商务平台**:在线商店常常面临海量咨询请求的压力,而借助智能客服工具则可以在第一时间解答常见疑问,引导访客顺利完成购买流程; - **金融服务行业**:银行及其他金融机构也积极引入此类服务,用于账户查询、转账汇款指导等方面工作,既提高了效率又保障了安全性; - **电信运营商**:电话服务中心往往需要应对数以万计的日均来电量,此时拥有强大应变能力的人工智能助理无疑成为缓解人工坐席压力的有效手段之一。 ```python # 示例代码展示了一个简单的基于规则匹配的智能回复函数 def simple_chatbot_response(user_input): responses = { "你好": "您好!请问有什么可以帮助您的吗?", "再见": "感谢光临,祝您生活愉快!" } return responses.get(user_input.strip(), "抱歉,我太明白您的意思") print(simple_chatbot_response("你好")) ```
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值