Refactor datetime

This commit is contained in:
Chris Coutinho
2025-07-31 14:51:33 +02:00
parent 19631838bb
commit 75235d6013
+28 -27
View File
@@ -1,12 +1,11 @@
"""CalDAV client for NextCloud calendar operations.""" """CalDAV client for NextCloud calendar operations."""
import xml.etree.ElementTree as ET import xml.etree.ElementTree as ET
from datetime import datetime, date import datetime as dt
from typing import Dict, Any, List, Optional, Tuple from typing import Dict, Any, List, Optional, Tuple
import logging import logging
from httpx import HTTPStatusError from httpx import HTTPStatusError
from icalendar import Calendar, Event as ICalEvent, vRecur, Alarm from icalendar import Calendar, Event as ICalEvent, vRecur, Alarm
from datetime import timedelta
import uuid import uuid
from .base import BaseNextcloudClient from .base import BaseNextcloudClient
@@ -347,16 +346,16 @@ class CalendarClient(BaseNextcloudClient):
if start_str: # Only parse if start_datetime is provided if start_str: # Only parse if start_datetime is provided
if all_day: if all_day:
start_date = datetime.fromisoformat(start_str.split("T")[0]).date() start_date = dt.datetime.fromisoformat(start_str.split("T")[0]).date()
event.add("dtstart", start_date) event.add("dtstart", start_date)
if end_str: if end_str:
end_date = datetime.fromisoformat(end_str.split("T")[0]).date() end_date = dt.datetime.fromisoformat(end_str.split("T")[0]).date()
event.add("dtend", end_date) event.add("dtend", end_date)
else: else:
start_dt = datetime.fromisoformat(start_str.replace("Z", "+00:00")) start_dt = dt.datetime.fromisoformat(start_str.replace("Z", "+00:00"))
event.add("dtstart", start_dt) event.add("dtstart", start_dt)
if end_str: if end_str:
end_dt = datetime.fromisoformat(end_str.replace("Z", "+00:00")) end_dt = dt.datetime.fromisoformat(end_str.replace("Z", "+00:00"))
event.add("dtend", end_dt) event.add("dtend", end_dt)
# Add categories # Add categories
@@ -393,7 +392,7 @@ class CalendarClient(BaseNextcloudClient):
alarm = Alarm() alarm = Alarm()
alarm.add("action", "DISPLAY") alarm.add("action", "DISPLAY")
alarm.add("description", "Event reminder") alarm.add("description", "Event reminder")
alarm.add("trigger", timedelta(minutes=-reminder_minutes)) alarm.add("trigger", dt.timedelta(minutes=-reminder_minutes))
event.add_component(alarm) event.add_component(alarm)
# Add attendees # Add attendees
@@ -404,7 +403,7 @@ class CalendarClient(BaseNextcloudClient):
event.add("attendee", f"mailto:{email.strip()}") event.add("attendee", f"mailto:{email.strip()}")
# Add timestamps # Add timestamps
now = datetime.utcnow() now = dt.datetime.now(dt.UTC)
event.add("created", now) event.add("created", now)
event.add("dtstamp", now) event.add("dtstamp", now)
event.add("last-modified", now) event.add("last-modified", now)
@@ -432,8 +431,8 @@ class CalendarClient(BaseNextcloudClient):
# Handle dates # Handle dates
dtstart = component.get("dtstart") dtstart = component.get("dtstart")
if dtstart: if dtstart:
if isinstance(dtstart.dt, date) and not isinstance( if isinstance(dtstart.dt, dt.date) and not isinstance(
dtstart.dt, datetime dtstart.dt, dt.datetime
): ):
event_data["start_datetime"] = dtstart.dt.isoformat() event_data["start_datetime"] = dtstart.dt.isoformat()
event_data["all_day"] = True event_data["all_day"] = True
@@ -443,8 +442,8 @@ class CalendarClient(BaseNextcloudClient):
dtend = component.get("dtend") dtend = component.get("dtend")
if dtend: if dtend:
if isinstance(dtend.dt, date) and not isinstance( if isinstance(dtend.dt, dt.date) and not isinstance(
dtend.dt, datetime dtend.dt, dt.datetime
): ):
event_data["end_datetime"] = dtend.dt.isoformat() event_data["end_datetime"] = dtend.dt.isoformat()
else: else:
@@ -576,10 +575,12 @@ class CalendarClient(BaseNextcloudClient):
end_str = event.get("end_datetime", "") end_str = event.get("end_datetime", "")
if start_str and end_str: if start_str and end_str:
try: try:
start_dt = datetime.fromisoformat( start_dt = dt.datetime.fromisoformat(
start_str.replace("Z", "+00:00") start_str.replace("Z", "+00:00")
) )
end_dt = datetime.fromisoformat(end_str.replace("Z", "+00:00")) end_dt = dt.datetime.fromisoformat(
end_str.replace("Z", "+00:00")
)
duration_minutes = (end_dt - start_dt).total_seconds() / 60 duration_minutes = (end_dt - start_dt).total_seconds() / 60
if duration_minutes < filters["min_duration_minutes"]: if duration_minutes < filters["min_duration_minutes"]:
return False return False
@@ -630,9 +631,9 @@ class CalendarClient(BaseNextcloudClient):
try: try:
# Set default date range if not provided # Set default date range if not provided
if not date_range_start: if not date_range_start:
date_range_start = datetime.now().strftime("%Y-%m-%d") date_range_start = dt.datetime.now().strftime("%Y-%m-%d")
if not date_range_end: if not date_range_end:
end_date = datetime.now() + timedelta(days=7) end_date = dt.datetime.now() + dt.timedelta(days=7)
date_range_end = end_date.strftime("%Y-%m-%d") date_range_end = end_date.strftime("%Y-%m-%d")
# Get all events in the date range # Get all events in the date range
@@ -688,13 +689,13 @@ class CalendarClient(BaseNextcloudClient):
available_slots = [] available_slots = []
try: try:
current_date = datetime.fromisoformat(start_date) current_date = dt.datetime.fromisoformat(start_date)
end_date_dt = datetime.fromisoformat(end_date) end_date_dt = dt.datetime.fromisoformat(end_date)
while current_date <= end_date_dt: while current_date <= end_date_dt:
# Skip weekends if requested # Skip weekends if requested
if exclude_weekends and current_date.weekday() >= 5: if exclude_weekends and current_date.weekday() >= 5:
current_date += timedelta(days=1) current_date += dt.timedelta(days=1)
continue continue
# Generate slots for this day # Generate slots for this day
@@ -707,7 +708,7 @@ class CalendarClient(BaseNextcloudClient):
) )
available_slots.extend(day_slots) available_slots.extend(day_slots)
current_date += timedelta(days=1) current_date += dt.timedelta(days=1)
return available_slots[:10] # Limit to 10 slots return available_slots[:10] # Limit to 10 slots
@@ -717,7 +718,7 @@ class CalendarClient(BaseNextcloudClient):
def _generate_day_slots( def _generate_day_slots(
self, self,
date: datetime, date: dt.datetime,
busy_events: List[Dict[str, Any]], busy_events: List[Dict[str, Any]],
duration_minutes: int, duration_minutes: int,
business_hours_only: bool, business_hours_only: bool,
@@ -737,10 +738,10 @@ class CalendarClient(BaseNextcloudClient):
day_busy_periods = [] day_busy_periods = []
for event in busy_events: for event in busy_events:
try: try:
event_start = datetime.fromisoformat( event_start = dt.datetime.fromisoformat(
event["start_datetime"].replace("Z", "+00:00") event["start_datetime"].replace("Z", "+00:00")
) )
event_end = datetime.fromisoformat( event_end = dt.datetime.fromisoformat(
event["end_datetime"].replace("Z", "+00:00") event["end_datetime"].replace("Z", "+00:00")
) )
@@ -758,7 +759,7 @@ class CalendarClient(BaseNextcloudClient):
hour=start_hour, minute=0, second=0, microsecond=0 hour=start_hour, minute=0, second=0, microsecond=0
) )
end_time = date.replace(hour=end_hour, minute=0, second=0, microsecond=0) end_time = date.replace(hour=end_hour, minute=0, second=0, microsecond=0)
slot_duration = timedelta(minutes=duration_minutes) slot_duration = dt.timedelta(minutes=duration_minutes)
while current_time + slot_duration <= end_time: while current_time + slot_duration <= end_time:
slot_end = current_time + slot_duration slot_end = current_time + slot_duration
@@ -780,7 +781,7 @@ class CalendarClient(BaseNextcloudClient):
} }
) )
current_time += timedelta(minutes=30) # 30-minute increments current_time += dt.timedelta(minutes=30) # 30-minute increments
return slots return slots
@@ -803,8 +804,8 @@ class CalendarClient(BaseNextcloudClient):
for time_range in preferred_times: for time_range in preferred_times:
try: try:
start_str, end_str = time_range.split("-") start_str, end_str = time_range.split("-")
pref_start = datetime.strptime(start_str, "%H:%M").time() pref_start = dt.datetime.strptime(start_str, "%H:%M").time()
pref_end = datetime.strptime(end_str, "%H:%M").time() pref_end = dt.datetime.strptime(end_str, "%H:%M").time()
if pref_start <= slot_start <= pref_end: if pref_start <= slot_start <= pref_end:
return True return True