| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168 |
- package openTime
- import (
- "fmt"
- "regexp"
- "strings"
- "sync"
- "time"
- cherryString "github.com/cherry-game/cherry/extend/string"
- ctime "github.com/cherry-game/cherry/extend/time"
- )
- type (
- periodicParser struct{}
- periodic struct {
- mux sync.RWMutex
- times []*timeRange
- duration time.Duration
- interval time.Duration
- }
- )
- // 20230101/12:00|7d|21d
- func (p *periodicParser) Parse(params string) (OpenTime, error) {
- ts := strings.Split(params, "|")
- if len(ts) < 3 {
- return nil, fmt.Errorf("nonsupport params: %s", params)
- }
- startTime, err := parseDateTime(ts[0])
- if err != nil {
- return nil, err
- }
- reg, err := regexp.Compile(`(\d+)([yMdhm])`)
- if err != nil {
- return nil, err
- }
- duration, err := p.matchDuration(reg, ts[1])
- if err != nil {
- return nil, err
- }
- interval, err := p.matchDuration(reg, ts[2])
- if err != nil {
- return nil, err
- }
- now := ctime.Now()
- for now.After(startTime.Time) && now.After(startTime.Time.Add(duration)) {
- startTime.Time = startTime.Add(interval)
- }
- endTime := ctime.CherryTime{Time: startTime.Add(duration)}
- per := &periodic{
- times: []*timeRange{
- {
- startTime: startTime,
- endTime: endTime,
- },
- },
- duration: duration,
- interval: interval,
- }
- return per, nil
- }
- func (p *periodicParser) matchDuration(reg *regexp.Regexp, str string) (time.Duration, error) {
- ss := reg.FindStringSubmatch(str)
- if len(ss) < 3 {
- return 0, fmt.Errorf("nonsupport params: %s", str)
- }
- i, ok := cherryString.ToInt64(ss[1])
- if !ok {
- return 0, fmt.Errorf("nonsupport params: %s", str)
- }
- var duration time.Duration
- switch ss[2] {
- case "d":
- duration = time.Hour * 24 * time.Duration(i)
- case "h":
- duration = time.Hour * time.Duration(i)
- case "m":
- duration = time.Minute * time.Duration(i)
- default:
- return 0, fmt.Errorf("nonsupport params: %s", str)
- }
- return duration, nil
- }
- func (p *periodic) Between(t *ctime.CherryTime) bool {
- return p.between(0, t)
- }
- func (p *periodic) between(i int, t *ctime.CherryTime) bool {
- flag := false
- ts := p.times
- p.mux.RLock()
- for ; i < len(ts); i++ {
- node := ts[i]
- if t.After(node.startTime.Time) && t.Before(node.endTime.Time) {
- flag = true
- break
- }
- }
- p.mux.RUnlock()
- if !flag && i == len(ts) && t.After(ts[i-1].endTime.Time) {
- p.grow(t)
- return p.between(i, t)
- }
- // if i >= 10 {
- // p.trim(i-1)
- // }
- return flag
- }
- func (p *periodic) grow(t *ctime.CherryTime) {
- p.mux.Lock()
- defer p.mux.Unlock()
- t0 := p.times[len(p.times)-1]
- for t.After(t0.endTime.Time) {
- t1 := &timeRange{
- startTime: ctime.CherryTime{Time: t0.startTime.Add(p.interval)},
- endTime: ctime.CherryTime{Time: t0.startTime.Add(p.duration)},
- }
- p.times = append(p.times, t1)
- t0 = t1
- }
- }
- func (p *periodic) trim(i int) {
- p.mux.Lock()
- defer p.mux.Unlock()
- p.times = p.times[i:]
- }
- func (p *periodic) TimeRange(t *ctime.CherryTime) (ctime.CherryTime, ctime.CherryTime) {
- p.grow(t)
- var (
- startTime ctime.CherryTime
- endTime ctime.CherryTime
- )
- p.mux.RLock()
- for _, v := range p.times {
- if v.startTime.After(t.Time) || v.endTime.After(t.Time) {
- startTime = v.startTime
- endTime = v.endTime
- break
- }
- }
- p.mux.RUnlock()
- return startTime, endTime
- }
|