Coverage for src / local_deep_research / news / core / utils.py: 23%
35 statements
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
« prev ^ index » next coverage.py v7.12.0, created at 2026-01-11 00:51 +0000
1"""
2Core utilities for the news system.
3"""
5import os
6import uuid
7from datetime import datetime, timezone
8from zoneinfo import ZoneInfo
10from loguru import logger
13def get_local_date_string(settings_manager=None) -> str:
14 """
15 Get the current date as a string in the user's configured timezone.
17 This is used for replacing the YYYY-MM-DD placeholder in news subscriptions.
18 The timezone can be configured via:
19 1. The 'app.timezone' setting in the database
20 2. The TZ environment variable
21 3. Falls back to UTC if neither is set
23 Args:
24 settings_manager: Optional settings manager to read timezone setting from.
25 If not provided, will check TZ env var or default to UTC.
27 Returns:
28 str: Current date in ISO format (YYYY-MM-DD) in the configured timezone
29 """
30 tz_name = None
32 # Try to get timezone from settings
33 if settings_manager is not None:
34 try:
35 tz_name = settings_manager.get_setting("app.timezone")
36 except Exception as e:
37 logger.debug(f"Could not read timezone from settings: {e}")
39 # Fall back to TZ environment variable
40 if not tz_name:
41 tz_name = os.environ.get("TZ")
43 # Default to UTC if nothing is configured
44 if not tz_name:
45 tz_name = "UTC"
47 try:
48 tz = ZoneInfo(tz_name)
49 local_date = datetime.now(tz).date()
50 logger.debug(f"Using timezone {tz_name}, local date is {local_date}")
51 return local_date.isoformat()
52 except Exception as e:
53 logger.warning(
54 f"Invalid timezone '{tz_name}', falling back to UTC: {e}"
55 )
56 return datetime.now(timezone.utc).date().isoformat()
59def generate_card_id() -> str:
60 """
61 Generate a unique ID for a news card using UUID.
63 Returns:
64 str: A unique UUID string
65 """
66 return str(uuid.uuid4())
69def generate_subscription_id() -> str:
70 """
71 Generate a unique ID for a subscription.
73 Returns:
74 str: A unique UUID string
75 """
76 return str(uuid.uuid4())
79def utc_now() -> datetime:
80 """
81 Get current UTC time with timezone awareness.
83 Returns:
84 datetime: Current UTC time
85 """
86 return datetime.now(timezone.utc)
89def hours_ago(dt: datetime) -> float:
90 """
91 Calculate how many hours ago a datetime was.
93 Args:
94 dt: The datetime to compare
96 Returns:
97 float: Number of hours ago (negative if in future)
98 """
99 if dt.tzinfo is None:
100 dt = dt.replace(tzinfo=timezone.utc)
102 delta = utc_now() - dt
103 return delta.total_seconds() / 3600