Last active
May 29, 2025 10:48
-
-
Save byyam/94d0c55063119cf53fa8d402deda09d1 to your computer and use it in GitHub Desktop.
get workdays
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package workdays | |
import ( | |
"encoding/json" | |
"fmt" | |
"io" | |
"net/http" | |
"os" | |
"path/filepath" | |
"time" | |
) | |
const ( | |
workdayCacheDir = ".workday_cache" | |
workdayQueryURLTemplate = "https://api.apihubs.cn/holiday/get?year=%d&month=%s&workday=1&size=31" | |
) | |
// WorkdayInfo represents a single day's information from the API | |
type WorkdayInfo struct { | |
Year int `json:"year"` | |
Month int `json:"month"` | |
Date int `json:"date"` | |
YearWeek int `json:"yearweek"` | |
YearDay int `json:"yearday"` | |
LunarYear int `json:"lunar_year"` | |
LunarMonth int `json:"lunar_month"` | |
LunarDate int `json:"lunar_date"` | |
LunarYearDay int `json:"lunar_yearday"` | |
Week int `json:"week"` | |
Weekend int `json:"weekend"` | |
Workday int `json:"workday"` | |
Holiday int `json:"holiday"` | |
HolidayOr int `json:"holiday_or"` | |
HolidayOvertime int `json:"holiday_overtime"` | |
HolidayToday int `json:"holiday_today"` | |
HolidayLegal int `json:"holiday_legal"` | |
HolidayRecess int `json:"holiday_recess"` | |
} | |
// WorkdayResponse represents the complete API response | |
type WorkdayResponse struct { | |
Code int `json:"code"` | |
Msg string `json:"msg"` | |
Data struct { | |
List []WorkdayInfo `json:"list"` | |
Page int `json:"page"` | |
Size int `json:"size"` | |
Total int `json:"total"` | |
} `json:"data"` | |
} | |
// WorkdayParser defines the interface for parsing workday data | |
type WorkdayParser interface { | |
GetTotalWorkdays() int | |
GetWorkdayList() []WorkdayInfo | |
IsValid() bool | |
} | |
// Implement WorkdayParser for WorkdayResponse | |
func (w *WorkdayResponse) GetTotalWorkdays() int { | |
return w.Data.Total | |
} | |
func (w *WorkdayResponse) GetWorkdayList() []WorkdayInfo { | |
return w.Data.List | |
} | |
func (w *WorkdayResponse) IsValid() bool { | |
return w.Code == 0 | |
} | |
func verifyDate(dateStr string) error { | |
_, err := time.Parse("200601", dateStr) | |
if err != nil { | |
return fmt.Errorf("not a valid date: '%s'", dateStr) | |
} | |
return nil | |
} | |
func queryWorkdays(year, month int, verbose bool) (WorkdayParser, error) { | |
dateStr := fmt.Sprintf("%d%02d", year, month) | |
queryURL := fmt.Sprintf(workdayQueryURLTemplate, year, dateStr) | |
if verbose { | |
fmt.Println("Query workdays url:", queryURL) | |
} | |
client := &http.Client{Timeout: 10 * time.Second} | |
resp, err := client.Get(queryURL) | |
if err != nil { | |
return nil, fmt.Errorf("http request error: %v", err) | |
} | |
defer resp.Body.Close() | |
if resp.StatusCode != http.StatusOK { | |
return nil, fmt.Errorf("http request failed with status: %s", resp.Status) | |
} | |
body, err := io.ReadAll(resp.Body) | |
if err != nil { | |
return nil, fmt.Errorf("failed to read response body: %v", err) | |
} | |
var response WorkdayResponse | |
err = json.Unmarshal(body, &response) | |
if err != nil { | |
return nil, fmt.Errorf("failed to parse JSON response: %v", err) | |
} | |
if !response.IsValid() { | |
return nil, fmt.Errorf("api error: %v", response.Msg) | |
} | |
return &response, nil | |
} | |
func GetWorkdays(year, month int, verbose bool) int { | |
dateStr := fmt.Sprintf("%d%02d", year, month) | |
if err := verifyDate(dateStr); err != nil { | |
fmt.Println("error:", err) | |
return 0 | |
} | |
currentFileDir, _ := os.Getwd() | |
workdayCachePath := filepath.Join(currentFileDir, workdayCacheDir) | |
workdayCacheFile := filepath.Join(workdayCachePath, dateStr) | |
var parser WorkdayParser | |
if err := os.MkdirAll(workdayCachePath, os.ModePerm); err != nil { | |
fmt.Println("error creating cache directory:", err) | |
return 0 | |
} | |
if _, err := os.Stat(workdayCacheFile); os.IsNotExist(err) { | |
// Cache file does not exist, query the workdays | |
var err error | |
parser, err = queryWorkdays(year, month, verbose) | |
if err != nil { | |
fmt.Println("error:", err) | |
return 0 | |
} | |
// Cache the complete response | |
responseData, err := json.Marshal(parser.(*WorkdayResponse)) | |
if err != nil { | |
fmt.Println("error marshaling response:", err) | |
return 0 | |
} | |
if err := os.WriteFile(workdayCacheFile, responseData, 0644); err != nil { | |
fmt.Println("error writing cache file:", err) | |
return 0 | |
} | |
if verbose { | |
fmt.Println("write cache file to store workdays data") | |
} | |
} else { | |
// Cache file exists, read from it | |
content, err := os.ReadFile(workdayCacheFile) | |
if err != nil { | |
fmt.Println("error reading cache file:", err) | |
return 0 | |
} | |
var response WorkdayResponse | |
if err := json.Unmarshal(content, &response); err != nil { | |
fmt.Println("error parsing cache file:", err) | |
return 0 | |
} | |
parser = &response | |
if verbose { | |
fmt.Println("read cache file to get workdays data") | |
} | |
} | |
return parser.GetTotalWorkdays() | |
} | |
// IsWorkday checks if the given date is a workday | |
// If year, month, and day are all 0, it will use the current date | |
func IsWorkday(year, month, day int, verbose bool) bool { | |
if year == 0 && month == 0 && day == 0 { | |
now := time.Now() | |
year = now.Year() | |
month = int(now.Month()) | |
day = now.Day() | |
} | |
dateStr := fmt.Sprintf("%d%02d", year, month) | |
if err := verifyDate(dateStr); err != nil { | |
fmt.Println("error:", err) | |
return false | |
} | |
currentFileDir, _ := os.Getwd() | |
workdayCachePath := filepath.Join(currentFileDir, workdayCacheDir) | |
workdayCacheFile := filepath.Join(workdayCachePath, dateStr) | |
var parser WorkdayParser | |
if err := os.MkdirAll(workdayCachePath, os.ModePerm); err != nil { | |
fmt.Println("error creating cache directory:", err) | |
return false | |
} | |
if _, err := os.Stat(workdayCacheFile); os.IsNotExist(err) { | |
// Cache file does not exist, query the workdays | |
var err error | |
parser, err = queryWorkdays(year, month, verbose) | |
if err != nil { | |
fmt.Println("error:", err) | |
return false | |
} | |
// Cache the complete response | |
responseData, err := json.Marshal(parser.(*WorkdayResponse)) | |
if err != nil { | |
fmt.Println("error marshaling response:", err) | |
return false | |
} | |
if err := os.WriteFile(workdayCacheFile, responseData, 0644); err != nil { | |
fmt.Println("error writing cache file:", err) | |
return false | |
} | |
if verbose { | |
fmt.Println("write cache file to store workdays data") | |
} | |
} else { | |
// Cache file exists, read from it | |
content, err := os.ReadFile(workdayCacheFile) | |
if err != nil { | |
fmt.Println("error reading cache file:", err) | |
return false | |
} | |
var response WorkdayResponse | |
if err := json.Unmarshal(content, &response); err != nil { | |
fmt.Println("error parsing cache file:", err) | |
return false | |
} | |
parser = &response | |
if verbose { | |
fmt.Println("read cache file to get workdays data") | |
} | |
} | |
// Check if the specific day is a workday | |
for _, workday := range parser.GetWorkdayList() { | |
if workday.Date == year*10000+month*100+day { | |
return workday.Workday == 1 | |
} | |
} | |
return false | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.