Refactor datetime
This commit is contained in:
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user