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  )