Imports name this capability’s declared dependencies, which fune builds next to it in your project; each one links to its page.
from typing import List
from .charts_ticks_types import TimeInterval
from .dates_add_days import civil_from_days, days_from_civil, epoch_day_from_iso, iso_from_epoch_day ← from dates.add-days ^1.0.0 · built alongside by fune
# 1970-01-05, the first Monday on or after the epoch, as a day number.
_FIRST_MONDAY = 4
_MAX_TICKS = 10000
def _ceil_div(a: int, b: int) -> int:
return -((-a) // b)
def time_ticks(start: str, stop: str, interval: TimeInterval, step: int) -> List[str]:
"""Calendar boundaries between two dates, inclusive, anchored to the
calendar rather than to start so that panning does not move them: days by
(day - 1) % step, weeks since 1970-01-05, months by (month - 1) % step,
quarters by quarter of the year, years by year % step."""
if isinstance(step, bool) or not isinstance(step, int) or step < 1:
raise ValueError(f"step must be a whole number of at least 1, got {step}")
a = epoch_day_from_iso(start)
b = epoch_day_from_iso(stop)
reverse = b < a
lo, hi = (b, a) if reverse else (a, b)
days: List[int] = []
def add(day: int) -> None:
if len(days) >= _MAX_TICKS:
raise ValueError(f"too many ticks: more than {_MAX_TICKS}; use a longer interval or step")
days.append(day)
if interval == "day":
for d in range(lo, hi + 1):
if (civil_from_days(d).day - 1) % step == 0:
add(d)
elif interval == "week":
k = _ceil_div(lo - _FIRST_MONDAY, 7)
k = _ceil_div(k, step) * step
d = _FIRST_MONDAY + 7 * k
while d <= hi:
add(d)
d += 7 * step
elif interval in ("month", "quarter", "year"):
months = step if interval == "month" else 3 * step if interval == "quarter" else 12
first = civil_from_days(lo)
year, month = first.year, first.month
while True:
d = days_from_civil(year, month, 1)
if d > hi:
break
on_step = (month == 1 and year % step == 0) if interval == "year" else (month - 1) % months == 0
if d >= lo and on_step:
add(d)
month += 1
if month > 12:
month = 1
year += 1
else:
raise ValueError(f'unknown time interval "{interval}"')
ticks = [iso_from_epoch_day(d) for d in days]
if reverse:
ticks.reverse()
return ticks