utils and event logging
This commit is contained in:
109
utils/time_utils.py
Normal file
109
utils/time_utils.py
Normal file
@@ -0,0 +1,109 @@
|
||||
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}")
|
||||
Reference in New Issue
Block a user