/
schedule_string.go
128 lines (109 loc) · 3.84 KB
/
schedule_string.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
package scheduler
import (
"fmt"
"strconv"
"strings"
"time"
)
var (
// weekdays is a mapping of weekday strings to its respective values on the time package
weekdays = map[string]time.Weekday{
"sunday": time.Sunday,
"monday": time.Monday,
"tuesday": time.Tuesday,
"wednesday": time.Wednesday,
"thursday": time.Thursday,
"friday": time.Friday,
"saturday": time.Saturday,
}
// hourMinuteFormat represents the HH:MM time format
hourMinuteFormat = "15:04"
// unitToDuration is a mapping of time units to their respective durations
unitToDuration = map[string]time.Duration{
"second": time.Second,
"seconds": time.Second,
"minutes": time.Minute,
"minute": time.Minute,
"hours": time.Hour,
"hour": time.Hour,
"days": 24 * time.Hour,
"day": 24 * time.Hour,
"months": 30 * 24 * time.Hour,
"month": 30 * 24 * time.Hour,
"years": 365 * 24 * time.Hour,
"year": 365 * 24 * time.Hour,
}
)
// getNextScheduleDate parses a time schedule string into the date of the next execution
func getNextScheduleDate(schedule string) (time.Time, error) {
// Get the current time
now := now()
// Split the input schedule string into words
words := strings.Fields(schedule)
// Check if the first word is a number and the second word is a valid time unit
if len(words) == 2 {
num, err := strconv.Atoi(words[0])
if err != nil {
return time.Time{}, fmt.Errorf("Failed to parse schedule format '%s', invalid duration: %s, Error: %v", schedule, words[0], err)
}
unit := words[1]
duration, found := unitToDuration[unit]
if !found {
return time.Time{}, fmt.Errorf("Failed to parse schedule format '%s', invalid time unit: %s", schedule, unit)
}
nextTime := now.Add(time.Duration(num) * duration)
return nextTime, nil
}
if len(words) == 1 {
// Check if the input is a weekday
weekday, found := weekdays[words[0]]
if found {
daysUntilNextWeekday := int(weekday-now.Weekday()+7) % 7
nextTime := now.Add(time.Duration(daysUntilNextWeekday) * 24 * time.Hour)
nextTime = time.Date(nextTime.Year(), nextTime.Month(), nextTime.Day(), 0, 1, 0, 0, time.UTC)
// If the specified time has already passed for today, set it for the next week
if nextTime.Before(now) {
nextTime = nextTime.Add(time.Hour * 24 * 7)
}
return nextTime, nil
}
// Check if the input is a duration
duration, found := unitToDuration[words[0]]
if found {
nextTime := now.Add(duration)
return nextTime, nil
}
// Check if the input is a time in HH:MM format
t, err := time.Parse(hourMinuteFormat, words[0])
if err == nil {
nextTime := time.Date(now.Year(), now.Month(), now.Day(), t.Hour(), t.Minute(), 0, 0, time.UTC)
// If the specified time has already passed for today, set it for the next day
if now.After(nextTime) {
nextTime = nextTime.Add(24 * time.Hour)
}
return nextTime, nil
}
}
// Check if the input is a combination of a weekday and time
if len(words) == 3 {
if words[1] == "at" {
weekday, found := weekdays[words[0]]
if !found {
return time.Time{}, fmt.Errorf("Failed to parse schedule format '%s', invalid weekday: %s", schedule, words[0])
}
t, err := time.Parse(hourMinuteFormat, words[2])
if err != nil {
return time.Time{}, fmt.Errorf("Failed to parse schedule format '%s', invalid duration: %s, Error: %v", schedule, words[0], err)
}
daysUntilNextWeekday := int(weekday-now.Weekday()+7) % 7
nextTime := now.Add(time.Duration(daysUntilNextWeekday) * 24 * time.Hour)
nextTime = time.Date(nextTime.Year(), nextTime.Month(), nextTime.Day(), t.Hour(), t.Minute(), 0, 0, time.UTC)
// If the specified time has already passed for today, set it for the next week
if nextTime.Before(now) {
nextTime = nextTime.Add(time.Hour * 24 * 7)
}
return nextTime, nil
}
}
return time.Time{}, fmt.Errorf("Invalid schedule format: %s", schedule)
}