Date Generation Utilities¶
MoneyWarp provides convenient date generation functions powered by python-dateutil for robust and intelligent date arithmetic.
Why Date Generation Matters¶
Creating payment schedules manually is error-prone and tedious:
# ❌ Manual date creation (error-prone)
from datetime import datetime, timedelta
start_date = datetime(2024, 1, 31)
due_dates = []
for i in range(12):
# This breaks for months with different lengths!
due_dates.append(start_date + timedelta(days=30*i))
MoneyWarp's date utilities handle edge cases automatically:
# ✅ Smart date generation (robust)
from money_warp import generate_monthly_dates
from datetime import datetime
due_dates = generate_monthly_dates(datetime(2024, 1, 31), 12)
# Handles Feb 29, month lengths, leap years automatically!
Available Functions¶
Monthly Dates¶
Generate monthly payment schedules with intelligent end-of-month handling:
from money_warp import generate_monthly_dates
from datetime import datetime
# Basic monthly dates
dates = generate_monthly_dates(datetime(2024, 1, 15), 12)
print(f"12 monthly payments starting Jan 15")
# End-of-month intelligence
eom_dates = generate_monthly_dates(datetime(2024, 1, 31), 4)
# Results: [Jan 31, Feb 29, Mar 31, Apr 30]
# Each date anchors to the original day (31st), clamped per month
Bi-weekly Dates¶
Perfect for payroll-aligned payment schedules:
from money_warp import generate_biweekly_dates
# 26 bi-weekly payments (roughly 1 year)
dates = generate_biweekly_dates(datetime(2024, 1, 1), 26)
print(f"Payment every 14 days")
# Great for matching payroll schedules
payroll_dates = generate_biweekly_dates(datetime(2024, 1, 5), 26) # Fridays
Weekly Dates¶
For high-frequency payment schedules:
from money_warp import generate_weekly_dates
# Weekly payments for a year
dates = generate_weekly_dates(datetime(2024, 1, 1), 52)
print(f"52 weekly payments")
Quarterly Dates¶
Business-friendly quarterly schedules:
from money_warp import generate_quarterly_dates
# Quarterly payments
dates = generate_quarterly_dates(datetime(2024, 1, 15), 8) # 2 years
print(f"Quarterly payments: Q1, Q2, Q3, Q4...")
# End-of-quarter example
quarter_end = generate_quarterly_dates(datetime(2024, 3, 31), 4)
# Results: [Mar 31, Jun 30, Sep 30, Dec 31]
# Anchors to original day (31st), clamped for 30-day months
Annual Dates¶
For long-term loans and investments:
from money_warp import generate_annual_dates
# 30-year mortgage payments
dates = generate_annual_dates(datetime(2024, 1, 1), 30)
# Leap year handling
leap_dates = generate_annual_dates(datetime(2024, 2, 29), 5)
# Results: [2024-02-29, 2025-02-28, 2026-02-28, 2027-02-28, 2028-02-29]
# Anchors to 29th — returns to Feb 29 when the next leap year arrives
Custom Intervals¶
For any custom payment frequency:
from money_warp import generate_custom_interval_dates
# Every 45 days
dates = generate_custom_interval_dates(datetime(2024, 1, 1), 8, 45)
# Every 10 days (short-term financing)
short_term = generate_custom_interval_dates(datetime(2024, 1, 1), 12, 10)
Integration with Loans¶
Generators return List[datetime]; Loan expects calendar due_dates: List[date]. Convert with to_date from money_warp.tz:
from datetime import datetime
from money_warp import Loan, Money, InterestRate, generate_monthly_dates
from money_warp.tz import to_date
# Generate payment dates, then strip to calendar dates for the loan
due_dates = [to_date(d) for d in generate_monthly_dates(datetime(2024, 1, 15), 24)]
# Create loan with generated dates
loan = Loan(
principal=Money("25000"),
interest_rate=InterestRate("4.5% annual"),
due_dates=due_dates
)
# Get payment schedule
schedule = loan.get_amortization_schedule()
print(f"Monthly payment: {schedule[0].payment_amount}")
Edge Cases Handled¶
End-of-Month Intelligence¶
# Starting on January 31st
dates = generate_monthly_dates(datetime(2024, 1, 31), 6)
# Results (each date anchored to original day 31):
# Jan 31 (start)
# Feb 29 (leap year, clamped from 31)
# Mar 31 (back to 31)
# Apr 30 (April has 30 days, clamped)
# May 31 (back to 31)
# Jun 30 (June has 30 days, clamped)
for i, date in enumerate(dates, 1):
print(f"Payment {i}: {date} (day {date.day})")
Leap Year Handling¶
# Annual payments starting on leap day
leap_dates = generate_annual_dates(datetime(2024, 2, 29), 5)
# Results (anchored to 29th):
# 2024-02-29 (leap year)
# 2025-02-28 (not leap year, clamped)
# 2026-02-28 (not leap year, clamped)
# 2027-02-28 (not leap year, clamped)
# 2028-02-29 (leap year again, back to 29)
Quarter-End Variations¶
# Starting at end of March (31 days)
quarter_dates = generate_quarterly_dates(datetime(2024, 3, 31), 4)
# Results (anchored to 31st):
# Mar 31 (start)
# Jun 30 (June has 30 days, clamped)
# Sep 30 (September has 30 days, clamped)
# Dec 31 (back to 31)
Real-World Examples¶
Mortgage with Monthly Payments¶
from datetime import datetime
from money_warp import Loan, Money, InterestRate, generate_monthly_dates
from money_warp.tz import to_date
# 30-year mortgage starting mid-month
start_date = datetime(2024, 1, 15)
payment_dates = [to_date(d) for d in generate_monthly_dates(start_date, 360)] # 30 years * 12 months
mortgage = Loan(
principal=Money("400000"), # $400k house
interest_rate=InterestRate("6.5% annual"),
due_dates=payment_dates
)
print(f"30-year mortgage with {len(payment_dates)} payments")
print(f"First payment: {payment_dates[0]}")
print(f"Final payment: {payment_dates[-1]}")
Bi-weekly Auto Loan¶
from datetime import datetime
from money_warp import Loan, Money, InterestRate, generate_biweekly_dates
from money_warp.tz import to_date
# Bi-weekly auto loan (pays off faster)
biweekly_dates = [to_date(d) for d in generate_biweekly_dates(datetime(2024, 1, 5), 130)] # ~5 years
auto_loan = Loan(
principal=Money("35000"),
interest_rate=InterestRate("7.2% annual"),
due_dates=biweekly_dates
)
print(f"Bi-weekly auto loan: {len(biweekly_dates)} payments")
Business Quarterly Loan¶
from datetime import datetime
from money_warp import Loan, Money, InterestRate, generate_quarterly_dates
from money_warp.tz import to_date
# Business loan with quarterly payments
quarterly_dates = [to_date(d) for d in generate_quarterly_dates(datetime(2024, 3, 31), 20)] # 5 years
business_loan = Loan(
principal=Money("100000"),
interest_rate=InterestRate("8.5% annual"),
due_dates=quarterly_dates
)
print(f"Business loan: {len(quarterly_dates)} quarterly payments")
API Reference¶
Function Signatures¶
def generate_monthly_dates(start_date: datetime, num_payments: int) -> List[datetime]:
"""Generate monthly payment dates with smart end-of-month handling."""
def generate_biweekly_dates(start_date: datetime, num_payments: int) -> List[datetime]:
"""Generate bi-weekly payment dates (every 14 days)."""
def generate_weekly_dates(start_date: datetime, num_payments: int) -> List[datetime]:
"""Generate weekly payment dates (every 7 days)."""
def generate_quarterly_dates(start_date: datetime, num_payments: int) -> List[datetime]:
"""Generate quarterly payment dates (every 3 months)."""
def generate_annual_dates(start_date: datetime, num_payments: int) -> List[datetime]:
"""Generate annual payment dates (every 12 months)."""
def generate_custom_interval_dates(
start_date: datetime, num_payments: int, interval_days: int
) -> List[datetime]:
"""Generate payment dates with custom day intervals."""
Error Handling¶
All functions validate inputs and raise clear errors:
# Invalid payment count
try:
generate_monthly_dates(datetime(2024, 1, 1), 0)
except ValueError as e:
print(e) # "Number of payments must be positive"
# Invalid interval
try:
generate_custom_interval_dates(datetime(2024, 1, 1), 5, -1)
except ValueError as e:
print(e) # "Interval days must be positive"
Key Benefits¶
Robust Date Arithmetic¶
- Powered by python-dateutil: Industry-standard date manipulation
- Smart month handling: Handles varying month lengths automatically
- Leap year aware: Correctly handles February 29th edge cases
Simple API¶
- Type-safe: Full type annotations and validation
- Minimal parameters: Just
datetimeandint, no complex options - Consistent behavior: All functions follow the same patterns
Immediate Integration¶
- Loan compatibility: Pass
[to_date(d) for d in dates]intoLoan— generators yielddatetime, loan due dates aredate - Time Machine support: All dates work with
Warpfor temporal analysis - Schedule generation: Seamless integration with payment schedulers
MoneyWarp's date utilities eliminate the complexity and bugs of manual date arithmetic, letting you focus on financial modeling instead of calendar math!