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  }