go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/gce/api/config/v1/schedule.go (about)

     1  // Copyright 2019 The LUCI Authors.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //      http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package config
    16  
    17  import (
    18  	"time"
    19  
    20  	"google.golang.org/genproto/googleapis/type/dayofweek"
    21  
    22  	"go.chromium.org/luci/common/errors"
    23  	"go.chromium.org/luci/config/validation"
    24  )
    25  
    26  // isSameDay returns whether the given time.Weekday and dayofweek.DayOfWeek
    27  // represent the same day of the week.
    28  func isSameDay(wkd time.Weekday, dow dayofweek.DayOfWeek) bool {
    29  	switch dow {
    30  	case dayofweek.DayOfWeek_DAY_OF_WEEK_UNSPECIFIED:
    31  		return false
    32  	case dayofweek.DayOfWeek_SUNDAY:
    33  		// time.Weekday has Sunday == 0, dayofweek.DayOfWeek has Sunday == 7.
    34  		return wkd == time.Sunday
    35  	default:
    36  		// For all other values, time.Weekday == dayofweek.DayOfWeek.
    37  		return int(wkd) == int(dow)
    38  	}
    39  }
    40  
    41  // mostRecentStart returns the most recent start time for this schedule relative
    42  // to the given time. The date in the returned time.Time will be the most recent
    43  // date falling on the day of the week specified in this schedule which results
    44  // in the returned time being equal to or before the given time.
    45  func (s *Schedule) mostRecentStart(now time.Time) (time.Time, error) {
    46  	t, err := s.GetStart().toTime()
    47  	if err != nil {
    48  		return time.Time{}, err
    49  	}
    50  	now = now.In(t.Location())
    51  	// toTime returns a time relative to the current date. Change it to be relative to the given date.
    52  	t = time.Date(now.Year(), now.Month(), now.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), t.Location())
    53  	if s.GetStart().Day == dayofweek.DayOfWeek_DAY_OF_WEEK_UNSPECIFIED {
    54  		return time.Time{}, errors.Reason("day must be specified").Err()
    55  	}
    56  	for !isSameDay(t.Weekday(), s.GetStart().Day) {
    57  		t = t.Add(time.Hour * -24)
    58  	}
    59  	if t.After(now) {
    60  		t = t.Add(time.Hour * -24 * 7)
    61  	}
    62  	return t, nil
    63  }
    64  
    65  // Validate validates this schedule.
    66  func (s *Schedule) Validate(c *validation.Context) {
    67  	if s.GetMin() < 0 {
    68  		c.Errorf("minimum amount must be non-negative")
    69  	}
    70  	if s.GetMax() < 0 {
    71  		c.Errorf("maximum amount must be non-negative")
    72  	}
    73  	if s.GetMin() > s.GetMax() {
    74  		c.Errorf("minimum amount must not exceed maximum amount")
    75  	}
    76  	c.Enter("length")
    77  	s.GetLength().Validate(c)
    78  	switch n, err := s.Length.ToSeconds(); {
    79  	case err != nil:
    80  		c.Errorf("%s", err)
    81  	case n == 0:
    82  		c.Errorf("duration or seconds is required")
    83  	}
    84  	c.Exit()
    85  	c.Enter("start")
    86  	s.GetStart().Validate(c)
    87  	c.Exit()
    88  }