fix(config): 统一 APP_TIMEZONE 至 Config 类,修复 wallet 循环导入

将散落在 scheduler / stats_aggregator / daily_usage_ledger / routes
中的 os.getenv("APP_TIMEZONE") 收归 Config.app_timezone,消除
wallet → system → maintenance_scheduler → user.preference → wallet
的循环导入链。
This commit is contained in:
LewisPen
2026-03-13 10:54:21 +08:00
parent e9678ea899
commit ded6b5b081
7 changed files with 18 additions and 16 deletions

View File

@@ -5,7 +5,6 @@
from __future__ import annotations
import os
from datetime import datetime, timedelta, timezone
from typing import Any, Literal
from zoneinfo import ZoneInfo
@@ -18,6 +17,7 @@ from sqlalchemy.orm import Session
from src.api.base.admin_adapter import AdminApiAdapter
from src.api.base.context import ApiRequestContext
from src.api.base.pipeline import ApiRequestPipeline
from src.config import config
from src.core.exceptions import InvalidRequestException, NotFoundException
from src.core.logger import logger
from src.database import get_db, get_db_context
@@ -27,8 +27,7 @@ from src.services.user.apikey import ApiKeyService
from src.services.user.bulk_cleanup import pre_clean_api_key
from src.services.wallet import WalletService
# 应用时区配置,默认为 Asia/Shanghai
APP_TIMEZONE = ZoneInfo(os.getenv("APP_TIMEZONE", "Asia/Shanghai"))
APP_TIMEZONE = ZoneInfo(config.app_timezone)
def parse_expiry_date(date_str: str | None) -> datetime | None:

View File

@@ -647,12 +647,12 @@ class UserDashboardStatsAdapter(DashboardAdapter):
async def handle(self, context: ApiRequestContext) -> Any: # type: ignore[override]
from zoneinfo import ZoneInfo
from src.services.system.stats_aggregator import APP_TIMEZONE
from src.config import config
db = context.db
user = context.user
# 使用业务时区计算日期,确保与用户感知的"今天"一致
app_tz = ZoneInfo(APP_TIMEZONE)
app_tz = ZoneInfo(config.app_timezone)
now_local = datetime.now(app_tz)
today_local = now_local.replace(hour=0, minute=0, second=0, microsecond=0)
# 转换为 UTC 用于数据库查询
@@ -1159,9 +1159,9 @@ class DashboardDailyStatsAdapter(DashboardAdapter):
# 使用业务时区计算日期,确保每日统计与业务日期一致
from zoneinfo import ZoneInfo
from src.services.system.stats_aggregator import APP_TIMEZONE
from src.config import config
app_tz = ZoneInfo(APP_TIMEZONE)
app_tz = ZoneInfo(config.app_timezone)
now_local = datetime.now(app_tz)
today_local = now_local.replace(hour=0, minute=0, second=0, microsecond=0)
# 转换为 UTC 用于数据库查询

View File

@@ -87,6 +87,9 @@ class Config:
# 注意: allow_credentials=True 时不能使用 allow_origins=["*"]
self.cors_allow_credentials = os.getenv("CORS_ALLOW_CREDENTIALS", "true").lower() == "true"
# 应用时区配置(用于定时任务、账单日期等业务逻辑)
self.app_timezone = os.getenv("APP_TIMEZONE", "Asia/Shanghai")
# 管理员账户配置(用于初始化)
self.admin_email = os.getenv("ADMIN_EMAIL", "admin@localhost")
self.admin_username = os.getenv("ADMIN_USERNAME", "admin")

View File

@@ -11,7 +11,7 @@ from src.services.system.maintenance_scheduler import (
MaintenanceScheduler,
get_maintenance_scheduler,
)
from src.services.system.scheduler import APP_TIMEZONE, TaskScheduler, get_scheduler
from src.services.system.scheduler import TaskScheduler, get_scheduler
from src.services.system.sync_stats import SyncStatsService
__all__ = [
@@ -23,5 +23,4 @@ __all__ = [
"SyncStatsService",
"TaskScheduler",
"get_scheduler",
"APP_TIMEZONE",
]

View File

@@ -8,7 +8,6 @@
from __future__ import annotations
import os
from datetime import datetime
from typing import Any, Callable
@@ -17,10 +16,11 @@ from apscheduler.triggers.cron import CronTrigger
from apscheduler.triggers.date import DateTrigger
from apscheduler.triggers.interval import IntervalTrigger
from src.config import config
from src.core.logger import logger
# 应用时区配置,默认为 Asia/Shanghai
APP_TIMEZONE = os.getenv("APP_TIMEZONE", "Asia/Shanghai")
# 统一从 config 读取,不再重复 os.getenv
APP_TIMEZONE = config.app_timezone
class TaskScheduler:

View File

@@ -5,7 +5,6 @@
from __future__ import annotations
import os
import uuid
from dataclasses import dataclass
from datetime import date, datetime, time, timedelta, timezone
@@ -16,6 +15,7 @@ from sqlalchemy import Date, Float, and_, case, cast, func, text
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import Session
from src.config import config
from src.core.logger import logger
from src.models.database import (
ApiKey,
@@ -36,8 +36,7 @@ from src.models.database import (
from src.models.database import User as DBUser
from src.services.system.time_range import TimeRangeParams, split_time_range_for_hourly
# App timezone (legacy defaults for dashboard)
APP_TIMEZONE = os.getenv("APP_TIMEZONE", "Asia/Shanghai")
APP_TIMEZONE = config.app_timezone
MIN_PERCENTILE_SAMPLES = 10

View File

@@ -8,10 +8,12 @@ from zoneinfo import ZoneInfo
from sqlalchemy import func
from sqlalchemy.orm import Session
from src.config import config
from src.core.logger import logger
from src.models.database import Usage, WalletDailyUsageLedger
from src.services.billing.precision import to_money_decimal
from src.services.system.scheduler import APP_TIMEZONE
APP_TIMEZONE = config.app_timezone
@dataclass(slots=True)