Files
docupulse/utils/time_utils.py
2025-05-29 15:19:42 +02:00

109 lines
3.1 KiB
Python

from datetime import datetime, timedelta
from typing import Union, Optional
def timeago(dt: Union[datetime, str], now: Optional[datetime] = None) -> str:
"""
Convert a datetime to a human-readable relative time string.
Args:
dt: The datetime to convert (can be datetime object or ISO format string)
now: Optional reference time (defaults to current time)
Returns:
str: Human-readable relative time string (e.g., "2 hours ago", "3 days ago")
"""
if isinstance(dt, str):
dt = datetime.fromisoformat(dt.replace('Z', '+00:00'))
if now is None:
now = datetime.utcnow()
diff = now - dt
# Less than a minute
if diff < timedelta(minutes=1):
return "just now"
# Less than an hour
if diff < timedelta(hours=1):
minutes = int(diff.total_seconds() / 60)
return f"{minutes} minute{'s' if minutes != 1 else ''} ago"
# Less than a day
if diff < timedelta(days=1):
hours = int(diff.total_seconds() / 3600)
return f"{hours} hour{'s' if hours != 1 else ''} ago"
# Less than a week
if diff < timedelta(days=7):
days = diff.days
return f"{days} day{'s' if days != 1 else ''} ago"
# Less than a month
if diff < timedelta(days=30):
weeks = int(diff.days / 7)
return f"{weeks} week{'s' if weeks != 1 else ''} ago"
# Less than a year
if diff < timedelta(days=365):
months = int(diff.days / 30)
return f"{months} month{'s' if months != 1 else ''} ago"
# More than a year
years = int(diff.days / 365)
return f"{years} year{'s' if years != 1 else ''} ago"
def format_datetime(dt: Union[datetime, str], format: str = "%Y-%m-%d %H:%M:%S") -> str:
"""
Format a datetime object or ISO string to a specified format.
Args:
dt: The datetime to format (can be datetime object or ISO format string)
format: The format string to use (defaults to "YYYY-MM-DD HH:MM:SS")
Returns:
str: Formatted datetime string
"""
if isinstance(dt, str):
dt = datetime.fromisoformat(dt.replace('Z', '+00:00'))
return dt.strftime(format)
def parse_datetime(dt_str: str) -> datetime:
"""
Parse a datetime string in various formats to a datetime object.
Args:
dt_str: The datetime string to parse
Returns:
datetime: Parsed datetime object
Raises:
ValueError: If the string cannot be parsed
"""
# Try ISO format first
try:
return datetime.fromisoformat(dt_str.replace('Z', '+00:00'))
except ValueError:
pass
# Try common formats
formats = [
"%Y-%m-%d %H:%M:%S",
"%Y-%m-%d %H:%M",
"%Y-%m-%d",
"%d/%m/%Y %H:%M:%S",
"%d/%m/%Y %H:%M",
"%d/%m/%Y",
"%m/%d/%Y %H:%M:%S",
"%m/%d/%Y %H:%M",
"%m/%d/%Y"
]
for fmt in formats:
try:
return datetime.strptime(dt_str, fmt)
except ValueError:
continue
raise ValueError(f"Could not parse datetime string: {dt_str}")