2017-01-07 01:46:18 +01:00
|
|
|
from datetime import datetime, timedelta
|
|
|
|
from typing import List, Optional
|
|
|
|
|
2017-11-16 00:55:49 +01:00
|
|
|
from analytics.lib.counts import CountStat
|
|
|
|
from zerver.lib.timestamp import floor_to_day, floor_to_hour, verify_UTC
|
|
|
|
|
2020-06-11 00:54:34 +02:00
|
|
|
|
2017-02-02 01:29:58 +01:00
|
|
|
# If min_length is None, returns end_times from ceiling(start) to floor(end), inclusive.
|
2017-01-07 01:46:18 +01:00
|
|
|
# If min_length is greater than 0, pads the list to the left.
|
|
|
|
# So informally, time_range(Sep 20, Sep 22, day, None) returns [Sep 20, Sep 21, Sep 22],
|
|
|
|
# and time_range(Sep 20, Sep 22, day, 5) returns [Sep 18, Sep 19, Sep 20, Sep 21, Sep 22]
|
2021-02-12 08:19:30 +01:00
|
|
|
def time_range(
|
|
|
|
start: datetime, end: datetime, frequency: str, min_length: Optional[int]
|
|
|
|
) -> List[datetime]:
|
2017-10-05 01:51:49 +02:00
|
|
|
verify_UTC(start)
|
|
|
|
verify_UTC(end)
|
2017-01-07 03:53:08 +01:00
|
|
|
if frequency == CountStat.HOUR:
|
2017-02-02 01:29:58 +01:00
|
|
|
end = floor_to_hour(end)
|
2017-01-07 01:46:18 +01:00
|
|
|
step = timedelta(hours=1)
|
2017-01-07 03:53:08 +01:00
|
|
|
elif frequency == CountStat.DAY:
|
2017-02-02 01:29:58 +01:00
|
|
|
end = floor_to_day(end)
|
2017-01-07 01:46:18 +01:00
|
|
|
step = timedelta(days=1)
|
|
|
|
else:
|
2020-06-10 06:41:04 +02:00
|
|
|
raise AssertionError(f"Unknown frequency: {frequency}")
|
2017-01-07 01:46:18 +01:00
|
|
|
|
|
|
|
times = []
|
|
|
|
if min_length is not None:
|
2021-02-12 08:19:30 +01:00
|
|
|
start = min(start, end - (min_length - 1) * step)
|
2017-01-07 01:46:18 +01:00
|
|
|
current = end
|
|
|
|
while current >= start:
|
|
|
|
times.append(current)
|
|
|
|
current -= step
|
2023-09-12 23:19:57 +02:00
|
|
|
times.reverse()
|
|
|
|
return times
|