go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/lucicfg/starlark/stdlib/internal/time.star (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 """API for defining time intervals.""" 16 17 def _duration(milliseconds): 18 """Returns a duration that represents the integer number of milliseconds. 19 20 Args: 21 milliseconds: integer with the requested number of milliseconds. Required. 22 23 Returns: 24 time.duration value. 25 """ 26 if type(milliseconds) != "int": 27 fail("time.duration: got %s, want int" % type(milliseconds)) 28 return __native__.make_duration(milliseconds) 29 30 def _epoch(layout, value, location): 31 """Returns epoch seconds for value interpreted as a time per layout in location. 32 33 Args: 34 layout: a string format showing how the reference time would be 35 interpreted, see golang's time.Parse. Required. 36 value: a string value to be parsed as a time. Required. 37 location: a string location, for example 'America/Los_Angeles'. Required. 38 39 Returns: 40 int epoch seconds for value. 41 """ 42 if type(layout) != "string": 43 fail("time.epoch: got %s as first argument, want string" % type(layout)) 44 if type(value) != "string": 45 fail("time.epoch: got %s as second argument, want string" % type(value)) 46 if type(location) != "string": 47 fail("time.epoch: got %s as third argument, want string" % type(location)) 48 return __native__.epoch(layout, value, location) 49 50 def _truncate(duration, precision): 51 """Truncates the precision of the duration to the given value. 52 53 For example `time.truncate(time.hour+10*time.minute, time.hour)` is 54 `time.hour`. 55 56 Args: 57 duration: a time.duration to truncate. Required. 58 precision: a time.duration with precision to truncate to. Required. 59 60 Returns: 61 Truncated time.duration value. 62 """ 63 if type(duration) != "duration": 64 fail("time.truncate: got %s as first argument, want duration" % type(duration)) 65 if type(precision) != "duration": 66 fail("time.truncate: got %s as second argument, want duration" % type(precision)) 67 return (duration // precision) * precision 68 69 _days = {"mon": 1, "tue": 2, "wed": 3, "thu": 4, "fri": 5, "sat": 6, "sun": 7} 70 71 def _day_index(name): 72 """E.g. 'Tue' -> 1.""" 73 idx = _days.get(name.lower()) 74 if idx == None: 75 fail("days_of_week: %r is not a valid 3-char abbreviated day of the week" % (name,)) 76 return idx 77 78 def _days_of_week(spec): 79 """Parses e.g. `Tue,Fri-Sun` into a list of day indexes, e.g. `[2, 5, 6, 7]`. 80 81 Monday is 1, Sunday is 7. The returned list is sorted and has no duplicates. 82 An empty string results in the empty list. 83 84 Args: 85 spec: a case-insensitive string with 3-char abbreviated days of the week. 86 Multiple terms are separated by a comma and optional spaces. Each term 87 is either a day (e.g. `Tue`), or a range (e.g. `Wed-Sun`). Required. 88 89 Returns: 90 A list of 1-based day indexes. Monday is 1. 91 """ 92 days = [] 93 for term in spec.split(","): 94 term = term.strip() 95 if not term: 96 continue 97 if "-" in term: 98 left, right = term.split("-") 99 left, right = left.strip(), right.strip() 100 li, ri = _day_index(left), _day_index(right) 101 if li > ri: 102 fail("days_of_week: bad range %r - %r is later than %r" % (term, left, right)) 103 days.extend(range(li, ri + 1)) 104 else: 105 days.append(_day_index(term)) 106 return sorted(set(days)) 107 108 # Time module provides a simple API for defining durations in a readable way, 109 # resembling golang's time.Duration. 110 # 111 # Durations are represented by integer-like values of time.duration(...) type, 112 # which internally hold a number of milliseconds. 113 # 114 # Durations can be added and subtracted from each other and multiplied by 115 # integers to get durations. They are also comparable to each other (but not 116 # to integers). Durations can also be divided by each other to get an integer, 117 # e.g. `time.hour / time.second` produces 3600. 118 # 119 # The best way to define a duration is to multiply an integer by a corresponding 120 # "unit" constant, for example `10 * time.second`. 121 # 122 # Following time constants are exposed: 123 # 124 # | Constant | Value (obviously) | 125 # |--------------------|---------------------------| 126 # | `time.zero` | `0 milliseconds` | 127 # | `time.millisecond` | `1 millisecond` | 128 # | `time.second` | `1000 * time.millisecond` | 129 # | `time.minute` | `60 * time.second` | 130 # | `time.hour` | `60 * time.minute` | 131 # | `time.day` | `24 * time.hour` | 132 # | `time.week` | `7 * time.day` | 133 time = struct( 134 duration = _duration, 135 epoch = _epoch, 136 truncate = _truncate, 137 138 # Handy for epoch's layout argument. 139 short_date = "2006-01-02 15:04:05", 140 zero = _duration(0), 141 millisecond = _duration(1), 142 second = _duration(1000), 143 minute = _duration(60 * 1000), 144 hour = _duration(60 * 60 * 1000), 145 day = _duration(24 * 60 * 60 * 1000), 146 week = _duration(7 * 24 * 60 * 60 * 1000), 147 days_of_week = _days_of_week, 148 )