add: 添加每月最后一天调度
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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(
|
||||
|
||||
Reference in New Issue
Block a user