From f02a88ebaa45eecdc614a0d33535da2bdb379118 Mon Sep 17 00:00:00 2001 From: shy3130 <415333856@qq.com> Date: Fri, 3 Jul 2026 13:31:33 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E6=B5=B7=E5=A4=96?= =?UTF-8?q?=E6=9C=8D=E5=8A=A1=E5=99=A8=E9=83=A8=E7=BD=B2=E5=90=8E=E4=BA=A4?= =?UTF-8?q?=E6=98=93=E6=97=B6=E6=AE=B5=E6=97=B6=E5=8C=BA=E8=AF=AF=E5=88=A4?= =?UTF-8?q?=E4=B8=BA=E4=BC=91=E5=B8=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 新增 backend/app/timezone.py 统一上海时区入口(ZoneInfo + UTC+8 兜底) - quote_service / depth_service 的 _is_trading_hours() 改用显式 Asia/Shanghai - Dockerfile 加 ENV TZ=Asia/Shanghai + tzdata,docker-compose.yml 加 TZ 环境变量 - 代码与容器双保险,解决裸 datetime.now() 在 UTC 容器下永远判为休市的问题 --- Dockerfile | 11 +++++++++++ backend/app/services/depth_service.py | 4 +++- backend/app/services/quote_service.py | 4 +++- backend/app/timezone.py | 28 +++++++++++++++++++++++++++ docker-compose.yml | 4 ++++ 5 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 backend/app/timezone.py diff --git a/Dockerfile b/Dockerfile index 36ec384..bd67178 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,17 @@ ARG PYPI_FALLBACK=https://mirrors.aliyun.com/pypi/simple ARG BACKEND_EXTRAS= WORKDIR /app +# 显式设置上海时区 + 安装 tzdata。 +# 容器默认 UTC, 不设的话 datetime.now() / date.today() 会用 UTC, +# 导致 A 股交易时段判断(依赖上海时间)在海外/UTC 服务器上永远误判为休市。 +# 代码层(app/timezone.py)已用 Asia/Shanghai 显式时区做双保险, +# 这里再设容器时区, 保证 date.today() 等裸时间调用也对。 +ENV TZ=Asia/Shanghai +RUN apt-get update && apt-get install -y --no-install-recommends tzdata && \ + ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && \ + echo $TZ > /etc/timezone && \ + rm -rf /var/lib/apt/lists/* + # 安装 uv(快) —— 国内镜像下三重兜底:主源 → 备用源 → 官方源, # 任一成功即可,避免单一镜像同步延迟/故障导致构建失败。 # uv 发版极频繁,国内镜像同步存在时间窗口,不锁版本且无 fallback 时 diff --git a/backend/app/services/depth_service.py b/backend/app/services/depth_service.py index 1e5c423..c03595b 100644 --- a/backend/app/services/depth_service.py +++ b/backend/app/services/depth_service.py @@ -29,6 +29,8 @@ from pathlib import Path import polars as pl +from app.timezone import now_shanghai as _now_shanghai + logger = logging.getLogger(__name__) @@ -579,7 +581,7 @@ class DepthService: @staticmethod def _is_trading_hours() -> bool: - now = datetime.now() + now = _now_shanghai() t = now.time() morning = dt_time(9, 25) <= t <= dt_time(11, 35) afternoon = dt_time(12, 55) <= t <= dt_time(15, 5) diff --git a/backend/app/services/quote_service.py b/backend/app/services/quote_service.py index 2948f9b..9b81f9b 100644 --- a/backend/app/services/quote_service.py +++ b/backend/app/services/quote_service.py @@ -30,6 +30,8 @@ from datetime import date, datetime, time as dt_time import polars as pl +from app.timezone import now_shanghai as _now_shanghai + logger = logging.getLogger(__name__) @@ -643,7 +645,7 @@ class QuoteService: @staticmethod def _is_trading_hours() -> bool: - now = datetime.now() + now = _now_shanghai() t = now.time() morning = dt_time(9, 15) <= t <= dt_time(11, 35) afternoon = dt_time(12, 55) <= t <= dt_time(15, 5) diff --git a/backend/app/timezone.py b/backend/app/timezone.py new file mode 100644 index 0000000..25c0886 --- /dev/null +++ b/backend/app/timezone.py @@ -0,0 +1,28 @@ +"""统一的时区工具。 + +A股交易时段判断、行情缓存键等均以上海时间为准。 +本模块集中提供一个获取"当前上海时间"的入口,避免各处裸用 +``datetime.now()`` / ``date.today()`` 导致海外服务器(容器默认 UTC) +把交易时段误判为休市。 + +优先使用标准库 ``zoneinfo`` 的 ``Asia/Shanghai``;当系统缺失 tzdata +(少数精简镜像)时退化为固定 UTC+8 偏移,保证功能可用。 +""" +from __future__ import annotations + +from datetime import datetime, timezone, timedelta + +# 上海时间固定偏移 UTC+8,作为 zoneinfo 不可用时的兜底。 +_SHANGHAI_OFFSET = timezone(timedelta(hours=8)) + +try: # pragma: no cover - 取决于运行环境 + from zoneinfo import ZoneInfo + + _SHANGHAI = ZoneInfo("Asia/Shanghai") +except Exception: # 缺 tzdata 时退化为固定偏移 + _SHANGHAI = _SHANGHAI_OFFSET + + +def now_shanghai() -> datetime: + """返回带上海时区信息的当前时间。""" + return datetime.now(_SHANGHAI) diff --git a/docker-compose.yml b/docker-compose.yml index 0399a4e..49fa008 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -10,6 +10,10 @@ services: container_name: TickFlow_Stock_Panel ports: - "${PORT:-3018}:3018" + environment: + # 容器默认 UTC 会误判 A 股交易时段, 显式设上海时间。 + # 与 Dockerfile 内的 ENV TZ 双保险, 也方便用 .env 覆盖。 + TZ: Asia/Shanghai env_file: - .env volumes: