add: 添加每月最后一天调度

This commit is contained in:
2026-06-20 11:46:50 +08:00
parent bce0c6188e
commit 161f266829
9 changed files with 49 additions and 23 deletions
+7 -4
View File
@@ -38,6 +38,7 @@ ALLOWED_ORIGINS = {
}
VALID_ACTIONS = {"copy", "sync", "move"}
VALID_SCHEDULE_KINDS = {"daily", "weekly", "monthly"}
MONTHDAY_LAST = 0
db_lock = threading.RLock()
scheduler_lock = threading.RLock()
@@ -142,13 +143,15 @@ def compute_next_run_at(
return iso(local_to_utc(candidate, offset_minutes))
if kind == "monthly":
if monthday is None or monthday < 1 or monthday > 31:
raise ValueError("scheduleMonthday must be 1-31")
if monthday is None or monthday < MONTHDAY_LAST or monthday > 31:
raise ValueError("scheduleMonthday must be 0-31")
for offset_months in range(0, 36):
year, month = add_months(local_after.year, local_after.month, offset_months)
if monthday > monthrange(year, month)[1]:
days_in_month = monthrange(year, month)[1]
candidate_day = days_in_month if monthday == MONTHDAY_LAST else monthday
if candidate_day > days_in_month:
continue
candidate = datetime(year, month, monthday, hour, minute)
candidate = datetime(year, month, candidate_day, hour, minute)
if candidate > local_after:
return iso(local_to_utc(candidate, offset_minutes))
raise ValueError("could not compute next monthly run")
+14
View File
@@ -48,6 +48,20 @@ class ComputeNextRunAtTest(unittest.TestCase):
"2026-03-31T23:00:00Z",
)
def test_monthly_last_day_uses_current_month_end(self):
after = datetime(2026, 2, 1, 0, 0, tzinfo=timezone.utc)
self.assertEqual(
compute_next_run_at("monthly", "23:00", 0, after, monthday=0),
"2026-02-28T23:00:00Z",
)
def test_monthly_last_day_rolls_forward_when_current_month_end_passed(self):
after = datetime(2026, 2, 28, 23, 0, tzinfo=timezone.utc)
self.assertEqual(
compute_next_run_at("monthly", "23:00", 0, after, monthday=0),
"2026-03-31T23:00:00Z",
)
def test_timezone_offset_is_applied_from_local_schedule_time(self):
after = datetime(2026, 6, 20, 12, 0, tzinfo=timezone.utc)
self.assertEqual(