feat: Refactor template handling, improve scheduler functions, and add timezone utilities

- Moved Jinja2 template setup to a shared configuration file (templates_config.py) for consistent usage across routers.
- Introduced timezone utilities in a new module (timezone.py) to handle UTC to local time conversions and formatting.
- Updated all relevant routers to use the new shared template configuration and timezone filters.
- Enhanced templates to utilize local time formatting for various datetime fields, improving user experience with timezone awareness.
This commit is contained in:
serversdwn
2026-01-23 06:05:39 +00:00
parent c771a86675
commit 8431784708
23 changed files with 418 additions and 141 deletions

173
backend/utils/timezone.py Normal file
View File

@@ -0,0 +1,173 @@
"""
Timezone utilities for Terra-View.
Provides consistent timezone handling throughout the application.
All database times are stored in UTC; this module converts for display.
"""
from datetime import datetime
from zoneinfo import ZoneInfo
from typing import Optional
from backend.database import SessionLocal
from backend.models import UserPreferences
# Default timezone if none set
DEFAULT_TIMEZONE = "America/New_York"
def get_user_timezone() -> str:
"""
Get the user's configured timezone from preferences.
Returns:
Timezone string (e.g., "America/New_York")
"""
db = SessionLocal()
try:
prefs = db.query(UserPreferences).filter_by(id=1).first()
if prefs and prefs.timezone:
return prefs.timezone
return DEFAULT_TIMEZONE
finally:
db.close()
def get_timezone_info(tz_name: str = None) -> ZoneInfo:
"""
Get ZoneInfo object for the specified or user's timezone.
Args:
tz_name: Timezone name, or None to use user preference
Returns:
ZoneInfo object
"""
if tz_name is None:
tz_name = get_user_timezone()
try:
return ZoneInfo(tz_name)
except Exception:
return ZoneInfo(DEFAULT_TIMEZONE)
def utc_to_local(dt: datetime, tz_name: str = None) -> datetime:
"""
Convert a UTC datetime to local timezone.
Args:
dt: Datetime in UTC (naive or aware)
tz_name: Target timezone, or None to use user preference
Returns:
Datetime in local timezone
"""
if dt is None:
return None
tz = get_timezone_info(tz_name)
# Assume naive datetime is UTC
if dt.tzinfo is None:
dt = dt.replace(tzinfo=ZoneInfo("UTC"))
return dt.astimezone(tz)
def local_to_utc(dt: datetime, tz_name: str = None) -> datetime:
"""
Convert a local datetime to UTC.
Args:
dt: Datetime in local timezone (naive or aware)
tz_name: Source timezone, or None to use user preference
Returns:
Datetime in UTC (naive, for database storage)
"""
if dt is None:
return None
tz = get_timezone_info(tz_name)
# Assume naive datetime is in local timezone
if dt.tzinfo is None:
dt = dt.replace(tzinfo=tz)
# Convert to UTC and strip tzinfo for database storage
return dt.astimezone(ZoneInfo("UTC")).replace(tzinfo=None)
def format_local_datetime(dt: datetime, fmt: str = "%Y-%m-%d %H:%M", tz_name: str = None) -> str:
"""
Format a UTC datetime as local time string.
Args:
dt: Datetime in UTC
fmt: strftime format string
tz_name: Target timezone, or None to use user preference
Returns:
Formatted datetime string in local time
"""
if dt is None:
return "N/A"
local_dt = utc_to_local(dt, tz_name)
return local_dt.strftime(fmt)
def format_local_time(dt: datetime, tz_name: str = None) -> str:
"""
Format a UTC datetime as local time (HH:MM format).
Args:
dt: Datetime in UTC
tz_name: Target timezone
Returns:
Time string in HH:MM format
"""
return format_local_datetime(dt, "%H:%M", tz_name)
def format_local_date(dt: datetime, tz_name: str = None) -> str:
"""
Format a UTC datetime as local date (YYYY-MM-DD format).
Args:
dt: Datetime in UTC
tz_name: Target timezone
Returns:
Date string
"""
return format_local_datetime(dt, "%Y-%m-%d", tz_name)
def get_timezone_abbreviation(tz_name: str = None) -> str:
"""
Get the abbreviation for a timezone (e.g., EST, EDT, PST).
Args:
tz_name: Timezone name, or None to use user preference
Returns:
Timezone abbreviation
"""
tz = get_timezone_info(tz_name)
now = datetime.now(tz)
return now.strftime("%Z")
# Common US timezone choices for settings dropdown
TIMEZONE_CHOICES = [
("America/New_York", "Eastern Time (ET)"),
("America/Chicago", "Central Time (CT)"),
("America/Denver", "Mountain Time (MT)"),
("America/Los_Angeles", "Pacific Time (PT)"),
("America/Anchorage", "Alaska Time (AKT)"),
("Pacific/Honolulu", "Hawaii Time (HT)"),
("UTC", "UTC"),
]