github.com/blend/go-sdk@v1.20220411.3/cron/daily_schedule.go (about) 1 /* 2 3 Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved 4 Use of this source code is governed by a MIT license that can be found in the LICENSE file. 5 6 */ 7 8 package cron 9 10 import ( 11 "fmt" 12 "strings" 13 "time" 14 ) 15 16 var ( 17 _ Schedule = (*DailySchedule)(nil) 18 _ fmt.Stringer = (*DailySchedule)(nil) 19 ) 20 21 // WeeklyAtUTC returns a schedule that fires on every of the given days at the given time by hour, minute and second in UTC. 22 func WeeklyAtUTC(hour, minute, second int, days ...time.Weekday) Schedule { 23 dayOfWeekMask := uint(0) 24 for _, day := range days { 25 dayOfWeekMask |= 1 << uint(day) 26 } 27 28 return &DailySchedule{DayOfWeekMask: dayOfWeekMask, TimeOfDayUTC: time.Date(0, 0, 0, hour, minute, second, 0, time.UTC)} 29 } 30 31 // DailyAtUTC returns a schedule that fires every day at the given hour, minute and second in UTC. 32 func DailyAtUTC(hour, minute, second int) Schedule { 33 return &DailySchedule{DayOfWeekMask: AllDaysMask, TimeOfDayUTC: time.Date(0, 0, 0, hour, minute, second, 0, time.UTC)} 34 } 35 36 // WeekdaysAtUTC returns a schedule that fires every week day at the given hour, minute and second in UTC> 37 func WeekdaysAtUTC(hour, minute, second int) Schedule { 38 return &DailySchedule{DayOfWeekMask: WeekDaysMask, TimeOfDayUTC: time.Date(0, 0, 0, hour, minute, second, 0, time.UTC)} 39 } 40 41 // WeekendsAtUTC returns a schedule that fires every weekend day at the given hour, minut and second. 42 func WeekendsAtUTC(hour, minute, second int) Schedule { 43 return &DailySchedule{DayOfWeekMask: WeekendDaysMask, TimeOfDayUTC: time.Date(0, 0, 0, hour, minute, second, 0, time.UTC)} 44 } 45 46 // DailySchedule is a schedule that fires every day that satisfies the DayOfWeekMask at the given TimeOfDayUTC. 47 type DailySchedule struct { 48 DayOfWeekMask uint 49 TimeOfDayUTC time.Time 50 } 51 52 func (ds DailySchedule) String() string { 53 if ds.DayOfWeekMask > 0 { 54 var days []string 55 for _, d := range DaysOfWeek { 56 if ds.checkDayOfWeekMask(d) { 57 days = append(days, d.String()) 58 } 59 } 60 return fmt.Sprintf("%s on %s each week", ds.TimeOfDayUTC.Format(time.RFC3339), strings.Join(days, ", ")) 61 } 62 return fmt.Sprintf("%s every day", ds.TimeOfDayUTC.Format(time.RFC3339)) 63 } 64 65 func (ds DailySchedule) checkDayOfWeekMask(day time.Weekday) bool { 66 trialDayMask := uint(1 << uint(day)) 67 bitwiseResult := (ds.DayOfWeekMask & trialDayMask) 68 return bitwiseResult > uint(0) 69 } 70 71 // Next implements Schedule. 72 func (ds DailySchedule) Next(after time.Time) time.Time { 73 if after.IsZero() { 74 after = Now() 75 } 76 77 todayInstance := time.Date(after.Year(), after.Month(), after.Day(), ds.TimeOfDayUTC.Hour(), ds.TimeOfDayUTC.Minute(), ds.TimeOfDayUTC.Second(), 0, time.UTC) 78 for day := 0; day < 8; day++ { 79 next := todayInstance.AddDate(0, 0, day) //the first run here it should be adding nothing, i.e. returning todayInstance ... 80 81 if ds.checkDayOfWeekMask(next.Weekday()) && next.After(after) { //we're on a day ... 82 return next 83 } 84 } 85 86 return Zero 87 }