一个Golang判断节假日的方法(通过解析gov.cn)
本方法参考自:golang 获取每年法定节假日 - 简书 (jianshu.com)
依赖:
go 1.20
require (
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
)
WorkDayUtil.go:
package workdayutil
import (
"errors"
"fmt"
"github.com/Azure/go-autorest/autorest/date"
"io"
"net/http"
"regexp"
"strings"
"time"
)
var (
holiday, workday, _ = GetDays()
)
// GetDays fjDays 法定节假日,全部列表
// GetDays sbDays 法定补休日,全部列表
func GetDays() (holiday, workday map[date.Date]interface{}, err error) {
var pUrl = "http://sousuo.gov.cn/s.htm?t=paper&advance=false&q=%E9%83%A8%E5%88%86%E8%8A%82%E5%81%87%E6%97%A5%E5%AE%89%E6%8E%92%E7%9A%84%E9%80%9A%E7%9F%A5"
bytes, err := HttpGet(pUrl, nil)
if err != nil {
return nil, nil, err
}
result, err := GetRegexpList(string(bytes), `<li class="res-list">(.*?)</li>`)
if err != nil {
return nil, nil, err
}
if len(result) == 0 {
return nil, nil, errors.New("解析错误")
}
// 拿第一个即可
var data = strings.TrimSpace(result[0][1])
if len(data) <= 0 {
return nil, nil, errors.New("data result")
}
linkUrl, err := GetRegexpItem(data, `a href="(.*?)"`)
if err != nil {
fmt.Println("linkUrl=err==", err)
return nil, nil, err
}
bytes, err = HttpGet(linkUrl, nil)
if err != nil {
fmt.Println("bytes=err==", err)
return nil, nil, err
}
year, err := GetRegexpItem(string(bytes), `国务院办公厅关于(.*?)年`)
if err != nil {
fmt.Println("year=err==", err)
return nil, nil, err
}
content, err := GetRegexpItem(string(bytes), `<div class="b12c pages_content".*?>(.*?)</div>`)
if err != nil {
fmt.Println("content=err==", err)
return nil, nil, err
}
ll, err := GetRegexpList(content, `</span>(.*?)</p>`)
if err != nil {
return nil, nil, err
}
holiday, workday = map[date.Date]interface{}{}, map[date.Date]interface{}{}
for _, c := range ll {
if len(c[1]) > 0 && !strings.Contains(c[1], "<") {
if strings.Contains(c[1], "。") {
var s = strings.Split(c[1], "。")
for _, str := range s {
if len(str) > 0 {
if strings.Contains(str, "放假") {
var t = strings.Split(str, "放假")[0]
if strings.Contains(t, "至") {
var st = strings.Split(t, "至")[0]
var et = strings.Split(t, "至")[1]
var y, m, d = GetDateTime(GetTimeFormat(year, "", st))
var ey, em, ed = GetDateTime(GetTimeFormat(year, m, et))
var times = GetDateRange(fmt.Sprintf("%s-%s-%s", y, m, d), fmt.Sprintf("%s-%s-%s", ey, em, ed))
for _, t := range times {
holiday[t] = nil
}
} else {
var y, m, d = GetDateTime(GetTimeFormat(year, "", t))
parseDate, _ := date.ParseDate(fmt.Sprintf("%s-%s-%s", y, m, d))
holiday[parseDate] = nil
}
}
if strings.Contains(str, "上班") {
if strings.Contains(str, "、") {
var ts = strings.Split(str, "、")
for _, t := range ts {
if strings.Contains(t, "日") {
var ymd = strings.Split(t, "日")
var y, m, d = GetDateTime(GetTimeFormat(year, "", ymd[0]+"日"))
//workday = append(workday, fmt.Sprintf("%s-%s-%s", y, m, d))
parseDate, _ := date.ParseDate(fmt.Sprintf("%s-%s-%s", y, m, d))
workday[parseDate] = nil
}
}
}
}
}
}
}
}
}
return
}
func GetTimeFormat(year, month, t string) string {
if strings.Contains(t, "月") {
if !strings.Contains(t, "年") {
t = fmt.Sprintf("%s年%s", year, t)
}
} else {
t = fmt.Sprintf("%s月%s", month, t)
if !strings.Contains(t, "年") {
t = fmt.Sprintf("%s年%s", year, t)
}
}
return t
}
func GetDateTime(t string) (year, month, day string) {
var ymd = strings.Split(t, "年")
var y = ymd[0] //2022
var md = ymd[1] //12月31日
var m = strings.Split(md, "月")[0]
var d = strings.Split(strings.Split(md, "月")[1], "日")[0]
if len(m) == 1 {
m = fmt.Sprintf("0%s", m)
}
if len(d) == 1 {
d = fmt.Sprintf("0%s", d)
}
return y, m, d
}
func GetRegexpItem(content string, regexpStr string) (s string, err error) {
if len(regexpStr) <= 0 {
return "", nil
}
// 处理回车换行
content = strings.Replace(content, "\r", "", len(content))
content = strings.Replace(content, "\n", "", len(content))
regexpStr = fmt.Sprintf("(?i)%s", regexpStr)
reg := regexp.MustCompile(regexpStr)
cs := reg.FindStringSubmatch(content)
if len(cs) > 1 {
// 去掉内容的前后空格
return strings.TrimSpace(cs[1]), nil
}
return "", errors.New(fmt.Sprintf("%s匹配错误,请检查网页", regexpStr))
}
// GetRegexpList 匹配符合正则的多个结果
func GetRegexpList(content string, regexpStr string) (s [][]string, err error) {
// 处理回车换行
content = strings.Replace(content, "\r", "", len(content))
content = strings.Replace(content, "\n", "", len(content))
regexpStr = fmt.Sprintf("(?i)%s", regexpStr)
reg := regexp.MustCompile(regexpStr)
result := reg.FindAllStringSubmatch(content, -1)
if len(result) <= 0 {
return nil, errors.New(fmt.Sprintf("%s匹配错误,请检查网页", regexpStr))
}
return result, nil
}
func HttpGet(url string, headers map[string]string) (response []byte, err error) {
resp, err := http.Get(url)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
return body, nil
}
// IsWorkday holiday 法定节假日日期列表["2023-04-29","2023-04-30","2023-05-01"...]
// IsWorkday workdays 法定补休日日期列表["2023-05-06"...]
func isWorkday(in date.Date, holidays map[date.Date]interface{}, workdays map[date.Date]interface{}) bool {
_, ok := workdays[in]
if ok {
return true
}
_, ok = holidays[in]
if ok {
return false
}
// 如果不在指定日期表中,则判断是否是周末
weekday := in.Weekday()
if weekday != time.Saturday && weekday != time.Sunday {
return true
}
return false
}
func IsWorkday(in date.Date) bool {
return isWorkday(in, holiday, workday)
}
func GetDateRange(start, end string) []date.Date {
startTime, _ := time.Parse("2006-01-02", start)
endTime, _ := time.Parse("2006-01-02", end)
var dates []date.Date
for i := 0; i <= int(endTime.Sub(startTime).Hours()/24); i++ {
currentTime := startTime.AddDate(0, 0, i)
d := currentTime.Format("2006-01-02")
dd, _ := date.ParseDate(d)
dates = append(dates, dd)
}
return dates
}
func Init() {
}
pUrl可能有变化,截止撰写时应为中国政府网站内搜索 (www.gov.cn)
调用方式:
parseDate, _ := date.ParseDate(time.Unix(batchLog.BizDate/1000, 0).Format(time.DateOnly))
workdayutil.IsWorkday(parseDate)