Files
EdgeAPI/internal/utils/time.go
GoEdgeLab 5a17ae9d79 v1.4.1
2024-07-27 14:15:25 +08:00

298 lines
6.8 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package utils
import (
"fmt"
"regexp"
"time"
"github.com/TeaOSLab/EdgeAPI/internal/errors"
"github.com/TeaOSLab/EdgeAPI/internal/utils/regexputils"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/types"
timeutil "github.com/iwind/TeaGo/utils/time"
)
// 分钟时间点
type timeDayMinute struct {
Day string
Minute string
}
// 分钟时间范围
type timeDayMinuteRange struct {
Day string
MinuteFrom string
MinuteTo string
}
// RangeDays 计算日期之间的所有日期格式为YYYYMMDD
func RangeDays(dayFrom string, dayTo string) ([]string, error) {
var ok = regexputils.YYYYMMDD.MatchString(dayFrom)
if !ok {
return nil, errors.New("invalid 'dayFrom'")
}
ok = regexputils.YYYYMMDD.MatchString(dayTo)
if !ok {
return nil, errors.New("invalid 'dayTo'")
}
if dayFrom > dayTo {
dayFrom, dayTo = dayTo, dayFrom
}
// 不能超过N天
maxDays := 100 - 1 // -1 是去掉默认加入的dayFrom
result := []string{dayFrom}
year := types.Int(dayFrom[:4])
month := types.Int(dayFrom[4:6])
day := types.Int(dayFrom[6:])
t := time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
for {
t = t.AddDate(0, 0, 1)
newDay := timeutil.Format("Ymd", t)
if newDay <= dayTo {
result = append(result, newDay)
} else {
break
}
maxDays--
if maxDays <= 0 {
break
}
}
return result, nil
}
// RangeMonths 计算日期之间的所有月份格式为YYYYMM
func RangeMonths(dayFrom string, dayTo string) ([]string, error) {
var ok = regexputils.YYYYMMDD.MatchString(dayFrom)
if !ok {
return nil, errors.New("invalid 'dayFrom'")
}
ok = regexputils.YYYYMMDD.MatchString(dayTo)
if !ok {
return nil, errors.New("invalid 'dayTo'")
}
if dayFrom > dayTo {
dayFrom, dayTo = dayTo, dayFrom
}
var result = []string{dayFrom[:6]}
var year = types.Int(dayFrom[:4])
var month = types.Int(dayFrom[4:6])
var day = types.Int(dayFrom[6:])
var t = time.Date(year, time.Month(month), day, 0, 0, 0, 0, time.Local)
for {
t = t.AddDate(0, 0, 20)
var newDay = timeutil.Format("Ymd", t)
if newDay <= dayTo {
var monthString = newDay[:6]
if !lists.ContainsString(result, monthString) {
result = append(result, monthString)
}
} else {
break
}
}
var endMonth = dayTo[:6]
if !lists.ContainsString(result, endMonth) {
result = append(result, endMonth)
}
return result, nil
}
// RangeHours 计算小时之间的所有小时格式为YYYYMMDDHH
func RangeHours(hourFrom string, hourTo string) ([]string, error) {
ok, err := regexp.MatchString(`^\d{10}$`, hourFrom)
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("invalid 'hourFrom'")
}
ok, err = regexp.MatchString(`^\d{10}$`, hourTo)
if err != nil {
return nil, err
}
if !ok {
return nil, errors.New("invalid 'hourTo'")
}
if hourFrom > hourTo {
hourFrom, hourTo = hourTo, hourFrom
}
// 不能超过N天
var maxHours = 100 - 1 // -1 是去掉默认加入的dayFrom
var result = []string{hourFrom}
var year = types.Int(hourFrom[:4])
var month = types.Int(hourFrom[4:6])
var day = types.Int(hourFrom[6:8])
var hour = types.Int(hourFrom[8:])
var t = time.Date(year, time.Month(month), day, hour, 0, 0, 0, time.Local)
for {
t = t.Add(1 * time.Hour)
var newHour = timeutil.Format("YmdH", t)
if newHour <= hourTo {
result = append(result, newHour)
} else {
break
}
maxHours--
if maxHours <= 0 {
break
}
}
return result, nil
}
// RangeMinutes 计算若干个时间点,返回结果为 [ [day1, minute1], [day2, minute2] ... ]
func RangeMinutes(toTime time.Time, count int, everyMinutes int32) []timeDayMinute {
var everySeconds = everyMinutes * 60
if everySeconds <= 0 {
everySeconds = 300
}
var result = []timeDayMinute{}
var fromTime = time.Unix(toTime.Unix()-int64(everySeconds)*int64(count-1), 0)
for {
var timestamp = fromTime.Unix() / int64(everySeconds) * int64(everySeconds)
result = append(result, timeDayMinute{
Day: timeutil.FormatTime("Ymd", timestamp),
Minute: timeutil.FormatTime("Hi", timestamp),
})
fromTime = time.Unix(fromTime.Unix()+int64(everySeconds), 0)
count--
if count <= 0 {
break
}
}
return result
}
// GroupMinuteRanges 将时间点分组
func GroupMinuteRanges(minutes []timeDayMinute) []timeDayMinuteRange {
var result = []*timeDayMinuteRange{}
var lastDay = ""
var lastRange *timeDayMinuteRange
for _, minute := range minutes {
if minute.Day != lastDay {
lastDay = minute.Day
lastRange = &timeDayMinuteRange{
Day: minute.Day,
MinuteFrom: minute.Minute,
MinuteTo: minute.Minute,
}
result = append(result, lastRange)
} else {
if lastRange != nil {
lastRange.MinuteTo = minute.Minute
}
}
}
var finalResult = []timeDayMinuteRange{}
for _, minutePtr := range result {
finalResult = append(finalResult, *minutePtr)
}
return finalResult
}
// RangeTimes 计算时间点
func RangeTimes(timeFrom string, timeTo string, everyMinutes int32) (result []string, err error) {
if everyMinutes <= 0 {
return nil, errors.New("invalid 'everyMinutes'")
}
var reg = regexp.MustCompile(`^\d{4}$`)
if !reg.MatchString(timeFrom) {
return nil, errors.New("invalid timeFrom '" + timeFrom + "'")
}
if !reg.MatchString(timeTo) {
return nil, errors.New("invalid timeTo '" + timeTo + "'")
}
if timeFrom > timeTo {
// swap
timeFrom, timeTo = timeTo, timeFrom
}
var everyMinutesInt = int(everyMinutes)
var fromHour = types.Int(timeFrom[:2])
var fromMinute = types.Int(timeFrom[2:])
var toHour = types.Int(timeTo[:2])
var toMinute = types.Int(timeTo[2:])
if fromMinute%everyMinutesInt == 0 {
result = append(result, timeFrom)
}
for {
fromMinute += everyMinutesInt
if fromMinute > 59 {
fromHour += fromMinute / 60
fromMinute = fromMinute % 60
}
if fromHour > toHour || (fromHour == toHour && fromMinute > toMinute) {
break
}
result = append(result, fmt.Sprintf("%02d%02d", fromHour, fromMinute))
}
return
}
// Range24HourTimes 计算24小时时间点
// 从 00:00 - 23:59
func Range24HourTimes(everyMinutes int32) ([]string, error) {
if everyMinutes <= 0 {
return nil, errors.New("invalid 'everyMinutes'")
}
return RangeTimes("0000", "2359", everyMinutes)
}
// LastDayInMonth 某月的最后一天
// month: YYYYMM
// 返回 YYYYMMDD
func LastDayInMonth(month string) (string, error) {
if !regexputils.YYYYMM.MatchString(month) {
return "", errors.New("invalid month '" + month + "'")
}
var year = types.Int(month[:4])
var monthInt = types.Int(month[4:])
return month + timeutil.Format("t", time.Date(year, time.Month(monthInt), 1, 0, 0, 0, 0, time.Local)), nil
}
// FixMonthMaxDay 修正日期最大值
func FixMonthMaxDay(day string) (string, error) {
if !regexputils.YYYYMMDD.MatchString(day) {
return "", errors.New("invalid day '" + day + "'")
}
maxDay, err := LastDayInMonth(day[:6])
if err != nil {
return "", err
}
if day > maxDay {
return maxDay, nil
}
return day, nil
}