diff --git a/README.md b/README.md
index 0720f0dd1..824e491cd 100644
--- a/README.md
+++ b/README.md
@@ -150,6 +150,7 @@
- macOS:`~/Library/Application Support/com.codexmanager.desktop/codexmanager.db`
- Linux:`~/.local/share/com.codexmanager.desktop/codexmanager.db`
- 如需调整数据库、代理、监听地址等运行配置,可继续查看 [环境变量与运行配置](docs/zh-CN/report/环境变量与运行配置说明.md)。
+- Docker 镜像默认使用 `TZ=Asia/Shanghai`;compose 示例会优先沿用部署环境里的 `TZ`,没有设置时回退到 `Asia/Shanghai`,其他地区部署时请改成对应 IANA 时区。
## 页面展示
### 桌面端
diff --git a/apps/src/app/settings/page.tsx b/apps/src/app/settings/page.tsx
index 702007ce7..7a46b4344 100644
--- a/apps/src/app/settings/page.tsx
+++ b/apps/src/app/settings/page.tsx
@@ -103,6 +103,7 @@ import {
compareEnvOverrideItems,
ensureModelForwardRuleRows,
formatFreeAccountModelLabel,
+ formatRuntimeTimeZoneLabel,
inferServiceBindPreview,
matchesRecommendedWorkerSettings,
normalizeEnvRiskLevel,
@@ -2069,9 +2070,15 @@ function AdminSettingsPage() {
- {snapshot.backgroundTasks.warmupCronEnabled
- ? t("定时账号预热已启用")
- : t("定时账号预热未启用。多个计划用 | 分隔。")}
+ {t(
+ "计划按服务端时区 {timeZone} 执行。多个计划用 | 分隔。",
+ {
+ timeZone: formatRuntimeTimeZoneLabel(
+ snapshot.runtimeTimeZone,
+ t("服务端本地时区"),
+ ),
+ },
+ )}
diff --git a/apps/src/app/settings/settings-page-helpers.ts b/apps/src/app/settings/settings-page-helpers.ts
index b21a974d9..ef3be2a3f 100644
--- a/apps/src/app/settings/settings-page-helpers.ts
+++ b/apps/src/app/settings/settings-page-helpers.ts
@@ -3,6 +3,7 @@ import type {
AppSettings,
BackgroundTaskSettings,
EnvOverrideCatalogItem,
+ RuntimeTimeZone,
} from "@/types";
export const ENV_DESCRIPTION_MAP: Record = {
@@ -227,6 +228,21 @@ export function stringifyNumber(value: number | null | undefined): string {
return value == null ? "" : String(value);
}
+export function formatRuntimeTimeZoneLabel(
+ runtimeTimeZone: RuntimeTimeZone | null | undefined,
+ localTimeZoneLabel = "服务端本地时区",
+): string {
+ const name = String(runtimeTimeZone?.name || "").trim();
+ const offset = String(runtimeTimeZone?.offset || "").trim();
+ const displayName =
+ name && name !== "Local" ? name : localTimeZoneLabel;
+ const normalizedOffset =
+ offset && !offset.toUpperCase().startsWith("UTC")
+ ? `UTC${offset.startsWith("+") || offset.startsWith("-") ? offset : `+${offset}`}`
+ : offset;
+ return normalizedOffset ? `${displayName} (${normalizedOffset})` : displayName;
+}
+
export function readNumberField(
source: Record,
key: string,
diff --git a/apps/src/lib/api/normalize.ts b/apps/src/lib/api/normalize.ts
index 809183fac..5fd363a71 100644
--- a/apps/src/lib/api/normalize.ts
+++ b/apps/src/lib/api/normalize.ts
@@ -18,6 +18,7 @@ import {
AppSettings,
BackgroundTaskSettings,
QuotaGuardSettings,
+ RuntimeTimeZone,
DeviceAuthInfo,
EnvOverrideCatalogItem,
InstalledPluginSummary,
@@ -83,6 +84,12 @@ const DEFAULT_QUOTA_GUARD: QuotaGuardSettings = {
allowAllLowQuotaFallback: true,
};
+const DEFAULT_RUNTIME_TIME_ZONE: RuntimeTimeZone = {
+ name: "Local",
+ offset: "",
+ source: "system",
+};
+
/**
* 函数 `asObject`
*
@@ -1697,6 +1704,15 @@ export function normalizeQuotaGuard(payload: unknown): QuotaGuardSettings {
};
}
+export function normalizeRuntimeTimeZone(payload: unknown): RuntimeTimeZone {
+ const source = asObject(payload);
+ return {
+ name: asString(source.name) || DEFAULT_RUNTIME_TIME_ZONE.name,
+ offset: asString(source.offset),
+ source: asString(source.source) || DEFAULT_RUNTIME_TIME_ZONE.source,
+ };
+}
+
export function normalizeEnvOverrideCatalog(payload: unknown): EnvOverrideCatalogItem[] {
return asArray(payload).reduce((result, item) => {
const source = asObject(item);
@@ -1803,6 +1819,7 @@ export function normalizeAppSettings(payload: unknown): AppSettings {
upstreamTotalTimeoutMs: asInteger(source.upstreamTotalTimeoutMs, 0, 0),
sseKeepaliveIntervalMs: asInteger(source.sseKeepaliveIntervalMs, 15_000, 1),
backgroundTasks: normalizeBackgroundTasks(source.backgroundTasks),
+ runtimeTimeZone: normalizeRuntimeTimeZone(source.runtimeTimeZone),
envOverrides: normalizeStringRecord(source.envOverrides),
envOverrideCatalog: normalizeEnvOverrideCatalog(source.envOverrideCatalog),
envOverrideReservedKeys: asArray(source.envOverrideReservedKeys).map((item) =>
diff --git a/apps/src/lib/i18n/messages/en.ts b/apps/src/lib/i18n/messages/en.ts
index 0419e71fe..bfefc6c22 100644
--- a/apps/src/lib/i18n/messages/en.ts
+++ b/apps/src/lib/i18n/messages/en.ts
@@ -558,6 +558,9 @@ export const EN_MESSAGES: MessageCatalog = {
网关保活线程: "Gateway keepalive worker",
令牌刷新轮询: "Token refresh polling",
"Worker 并发参数": "Worker concurrency",
+ "计划按服务端时区 {timeZone} 执行。多个计划用 | 分隔。":
+ "Schedule runs in server time zone {timeZone}. Separate multiple schedules with |.",
+ 服务端本地时区: "Server local time zone",
当前档位: "Current preset",
自定义: "Custom",
"搜索变量...": "Search variables...",
diff --git a/apps/src/lib/i18n/messages/ko.ts b/apps/src/lib/i18n/messages/ko.ts
index 75eb25642..05740fca7 100644
--- a/apps/src/lib/i18n/messages/ko.ts
+++ b/apps/src/lib/i18n/messages/ko.ts
@@ -474,6 +474,9 @@ export const KO_MESSAGES: MessageCatalog = {
网关策略: "게이트웨이 정책",
后台任务线程: "백그라운드 작업 스레드",
"Worker 并发参数": "Worker 동시성 설정",
+ "计划按服务端时区 {timeZone} 执行。多个计划用 | 分隔。":
+ "예약은 서버 시간대 {timeZone} 기준으로 실행됩니다. 여러 예약은 | 로 구분하세요.",
+ 服务端本地时区: "서버 로컬 시간대",
当前档位: "현재 프리셋",
自定义: "사용자 지정",
"搜索变量...": "변수 검색...",
diff --git a/apps/src/lib/i18n/messages/ru.ts b/apps/src/lib/i18n/messages/ru.ts
index 1017510a4..9bef22952 100644
--- a/apps/src/lib/i18n/messages/ru.ts
+++ b/apps/src/lib/i18n/messages/ru.ts
@@ -476,6 +476,9 @@ export const RU_MESSAGES: MessageCatalog = {
网关策略: "Политика шлюза",
后台任务线程: "Фоновые рабочие потоки",
"Worker 并发参数": "Параметры конкуренции Worker",
+ "计划按服务端时区 {timeZone} 执行。多个计划用 | 分隔。":
+ "Расписание выполняется в часовом поясе сервера {timeZone}. Несколько расписаний разделяйте символом |.",
+ 服务端本地时区: "Локальный часовой пояс сервера",
当前档位: "Текущий профиль",
自定义: "Свой",
"搜索变量...": "Поиск переменных...",
diff --git a/apps/src/lib/store/useAppStore.ts b/apps/src/lib/store/useAppStore.ts
index 0d184c6c2..a40fafa1a 100644
--- a/apps/src/lib/store/useAppStore.ts
+++ b/apps/src/lib/store/useAppStore.ts
@@ -124,6 +124,11 @@ export const useAppStore = create((set) => ({
warmupCronEnabled: false,
warmupCronExpression: "",
},
+ runtimeTimeZone: {
+ name: "Local",
+ offset: "",
+ source: "system",
+ },
envOverrides: {},
envOverrideCatalog: [],
envOverrideReservedKeys: [],
diff --git a/apps/src/types/settings.ts b/apps/src/types/settings.ts
index d428b13b9..f9a985407 100644
--- a/apps/src/types/settings.ts
+++ b/apps/src/types/settings.ts
@@ -27,6 +27,12 @@ export interface BackgroundTaskSettings {
warmupCronExpression: string;
}
+export interface RuntimeTimeZone {
+ name: string;
+ offset: string;
+ source: string;
+}
+
export interface QuotaGuardSettings {
enabled: boolean;
primaryMinRemainingPercent: number;
@@ -76,6 +82,7 @@ export interface AppSettings {
upstreamTotalTimeoutMs: number;
sseKeepaliveIntervalMs: number;
backgroundTasks: BackgroundTaskSettings;
+ runtimeTimeZone: RuntimeTimeZone;
envOverrides: Record;
envOverrideCatalog: EnvOverrideCatalogItem[];
envOverrideReservedKeys: string[];
diff --git a/apps/tests/settings-page-helpers.test.mjs b/apps/tests/settings-page-helpers.test.mjs
index 37b1781f9..b76c24c3f 100644
--- a/apps/tests/settings-page-helpers.test.mjs
+++ b/apps/tests/settings-page-helpers.test.mjs
@@ -60,3 +60,35 @@ test("compareEnvOverrideItems 将高风险请求语义项排在普通项之后",
"CODEXMANAGER_STRICT_REQUEST_PARAM_ALLOWLIST",
]);
});
+
+test("formatRuntimeTimeZoneLabel 显示后端传回的时区和偏移", () => {
+ assert.equal(
+ helpers.formatRuntimeTimeZoneLabel({
+ name: "Asia/Shanghai",
+ offset: "+08:00",
+ source: "TZ",
+ }),
+ "Asia/Shanghai (UTC+08:00)"
+ );
+
+ assert.equal(
+ helpers.formatRuntimeTimeZoneLabel({
+ name: "Local",
+ offset: "-05:00",
+ source: "system",
+ }),
+ "服务端本地时区 (UTC-05:00)"
+ );
+
+ assert.equal(
+ helpers.formatRuntimeTimeZoneLabel(
+ {
+ name: "Local",
+ offset: "+01:00",
+ source: "system",
+ },
+ "Server local time zone"
+ ),
+ "Server local time zone (UTC+01:00)"
+ );
+});
diff --git a/crates/service/src/app_settings/api/current.rs b/crates/service/src/app_settings/api/current.rs
index 0d1888798..de9f4e601 100644
--- a/crates/service/src/app_settings/api/current.rs
+++ b/crates/service/src/app_settings/api/current.rs
@@ -1,6 +1,7 @@
use crate::app_settings::{list_app_settings_map, listener_bind_addr_for_mode};
use crate::initialize_storage_if_needed;
use crate::{current_web_auth_mode, distribution_enabled, web_access_password_configured};
+use chrono::Local;
use codexmanager_core::rpc::types::ModelInfo;
use serde_json::Value;
use std::collections::BTreeMap;
@@ -78,6 +79,28 @@ fn normalize_service_bind_mode_value(raw: Option<&str>) -> &'static str {
}
}
+fn current_runtime_time_zone_value() -> Value {
+ let env_tz = std::env::var("TZ")
+ .ok()
+ .map(|value| value.trim().to_string())
+ .filter(|value| !value.is_empty());
+ let offset = Local::now().offset().to_string();
+ let source = if env_tz.is_some() { "TZ" } else { "system" };
+ let name = env_tz.unwrap_or_else(|| {
+ if offset == "+00:00" {
+ "UTC".to_string()
+ } else {
+ "Local".to_string()
+ }
+ });
+
+ serde_json::json!({
+ "name": name,
+ "offset": offset,
+ "source": source,
+ })
+}
+
/// 函数 `current_app_settings_value`
///
/// 作者: gaohongshun
@@ -97,6 +120,7 @@ pub(super) fn current_app_settings_value(
initialize_storage_if_needed()?;
sync_runtime_settings_from_storage();
let background_tasks = current_background_tasks_snapshot_value()?;
+ let runtime_time_zone = current_runtime_time_zone_value();
let update_auto_check = current_update_auto_check_enabled();
let persisted_close_to_tray = current_close_to_tray_on_close_setting();
let close_to_tray = close_to_tray_on_close.unwrap_or(persisted_close_to_tray);
@@ -259,6 +283,7 @@ pub(super) fn current_app_settings_value(
"webAccessPasswordConfigured": web_access_password_configured(),
});
if let Some(object) = result.as_object_mut() {
+ object.insert("runtimeTimeZone".to_string(), runtime_time_zone);
object.insert("webAuthMode".to_string(), current_web_auth_mode().into());
object.insert(
"webAuthModeOptions".to_string(),
diff --git a/crates/service/tests/app_settings.rs b/crates/service/tests/app_settings.rs
index d54315649..989741550 100644
--- a/crates/service/tests/app_settings.rs
+++ b/crates/service/tests/app_settings.rs
@@ -1032,6 +1032,37 @@ fn app_settings_get_defaults_codex_cli_guide_to_false() {
});
}
+#[test]
+fn app_settings_get_exposes_runtime_time_zone_from_tz_env() {
+ with_temp_db(|_| {
+ let _tz = override_env_vars(&[("TZ", Some("Asia/Shanghai"))]);
+
+ let snapshot = codexmanager_service::app_settings_get().expect("get app settings");
+ let runtime_time_zone = snapshot
+ .get("runtimeTimeZone")
+ .and_then(|value| value.as_object())
+ .expect("runtime time zone object");
+
+ assert_eq!(
+ runtime_time_zone.get("name").and_then(|value| value.as_str()),
+ Some("Asia/Shanghai")
+ );
+ assert_eq!(
+ runtime_time_zone
+ .get("source")
+ .and_then(|value| value.as_str()),
+ Some("TZ")
+ );
+ assert!(
+ runtime_time_zone
+ .get("offset")
+ .and_then(|value| value.as_str())
+ .is_some_and(|value| !value.is_empty()),
+ "runtime time zone should include an offset: {runtime_time_zone:?}"
+ );
+ });
+}
+
/// 函数 `sync_runtime_settings_from_storage_applies_saved_runtime_values`
///
/// 作者: gaohongshun
diff --git a/docker-compose.yml b/docker-compose.yml
index b60b244e6..a6390856d 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -12,6 +12,7 @@ services:
CODEXMANAGER_SERVICE_ADDR: 0.0.0.0:48760
CODEXMANAGER_WEB_ADDR: 0.0.0.0:48761
CODEXMANAGER_WEB_NO_OPEN: "1"
+ TZ: ${TZ:-Asia/Shanghai}
CODEXMANAGER_DB_PATH: /data/codexmanager.db
CODEXMANAGER_RPC_TOKEN_FILE: /data/codexmanager.rpc-token
CODEXMANAGER_GATEWAY_TRACE_STDOUT: "1"
diff --git a/docker/Dockerfile.all-in-one b/docker/Dockerfile.all-in-one
index b4cacf9ec..0daaf153d 100644
--- a/docker/Dockerfile.all-in-one
+++ b/docker/Dockerfile.all-in-one
@@ -46,10 +46,12 @@ FROM debian:bookworm-slim
ARG APP_USER=codexmanager
ARG APP_UID=10001
+ENV TZ=Asia/Shanghai
+
WORKDIR /app
RUN apt-get update \
- && apt-get install -y --no-install-recommends ca-certificates wget \
+ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates wget tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid ${APP_UID} ${APP_USER} \
&& useradd --system --uid ${APP_UID} --gid ${APP_UID} --home-dir /app --create-home --shell /usr/sbin/nologin ${APP_USER} \
diff --git a/docker/Dockerfile.service b/docker/Dockerfile.service
index 95a013c25..212cdd58c 100644
--- a/docker/Dockerfile.service
+++ b/docker/Dockerfile.service
@@ -13,10 +13,12 @@ FROM debian:bookworm-slim
ARG APP_USER=codexmanager
ARG APP_UID=10001
+ENV TZ=Asia/Shanghai
+
WORKDIR /app
RUN apt-get update \
- && apt-get install -y --no-install-recommends ca-certificates wget \
+ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates wget tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid ${APP_UID} ${APP_USER} \
&& useradd --system --uid ${APP_UID} --gid ${APP_UID} --home-dir /app --create-home --shell /usr/sbin/nologin ${APP_USER} \
diff --git a/docker/Dockerfile.service.release b/docker/Dockerfile.service.release
index 4d0a9f92b..1d7c25106 100644
--- a/docker/Dockerfile.service.release
+++ b/docker/Dockerfile.service.release
@@ -3,10 +3,12 @@ FROM debian:bookworm-slim
ARG APP_USER=codexmanager
ARG APP_UID=10001
+ENV TZ=Asia/Shanghai
+
WORKDIR /app
RUN apt-get update \
- && apt-get install -y --no-install-recommends ca-certificates wget \
+ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates wget tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid ${APP_UID} ${APP_USER} \
&& useradd --system --uid ${APP_UID} --gid ${APP_UID} --home-dir /app --create-home --shell /usr/sbin/nologin ${APP_USER} \
diff --git a/docker/Dockerfile.web b/docker/Dockerfile.web
index e066c04ce..f3d25989b 100644
--- a/docker/Dockerfile.web
+++ b/docker/Dockerfile.web
@@ -28,10 +28,12 @@ FROM debian:bookworm-slim
ARG APP_USER=codexmanager
ARG APP_UID=10001
+ENV TZ=Asia/Shanghai
+
WORKDIR /app
RUN apt-get update \
- && apt-get install -y --no-install-recommends ca-certificates wget \
+ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates wget tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid ${APP_UID} ${APP_USER} \
&& useradd --system --uid ${APP_UID} --gid ${APP_UID} --home-dir /app --create-home --shell /usr/sbin/nologin ${APP_USER} \
diff --git a/docker/Dockerfile.web.release b/docker/Dockerfile.web.release
index 80960d5e4..076f9a01a 100644
--- a/docker/Dockerfile.web.release
+++ b/docker/Dockerfile.web.release
@@ -3,10 +3,12 @@ FROM debian:bookworm-slim
ARG APP_USER=codexmanager
ARG APP_UID=10001
+ENV TZ=Asia/Shanghai
+
WORKDIR /app
RUN apt-get update \
- && apt-get install -y --no-install-recommends ca-certificates wget \
+ && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends ca-certificates wget tzdata \
&& rm -rf /var/lib/apt/lists/* \
&& groupadd --system --gid ${APP_UID} ${APP_USER} \
&& useradd --system --uid ${APP_UID} --gid ${APP_UID} --home-dir /app --create-home --shell /usr/sbin/nologin ${APP_USER} \
diff --git a/docker/docker-compose.all-in-one.yml b/docker/docker-compose.all-in-one.yml
index 24903436d..e8491356f 100644
--- a/docker/docker-compose.all-in-one.yml
+++ b/docker/docker-compose.all-in-one.yml
@@ -8,6 +8,7 @@ services:
CODEXMANAGER_SERVICE_ADDR: 0.0.0.0:48760
CODEXMANAGER_WEB_ADDR: 0.0.0.0:48761
CODEXMANAGER_WEB_NO_OPEN: "1"
+ TZ: ${TZ:-Asia/Shanghai}
CODEXMANAGER_DB_PATH: /data/codexmanager.db
CODEXMANAGER_RPC_TOKEN_FILE: /data/codexmanager.rpc-token
CODEXMANAGER_GATEWAY_TRACE_STDOUT: "1"
diff --git a/docker/docker-compose.release.yml b/docker/docker-compose.release.yml
index bd4570a2c..47bff7442 100644
--- a/docker/docker-compose.release.yml
+++ b/docker/docker-compose.release.yml
@@ -4,6 +4,7 @@ services:
restart: unless-stopped
environment:
CODEXMANAGER_SERVICE_ADDR: 0.0.0.0:48760
+ TZ: ${TZ:-Asia/Shanghai}
CODEXMANAGER_DB_PATH: /data/codexmanager.db
CODEXMANAGER_RPC_TOKEN_FILE: /data/codexmanager.rpc-token
volumes:
@@ -21,6 +22,7 @@ services:
CODEXMANAGER_WEB_ADDR: 0.0.0.0:48761
CODEXMANAGER_WEB_NO_SPAWN_SERVICE: "1"
CODEXMANAGER_SERVICE_ADDR: codexmanager-service:48760
+ TZ: ${TZ:-Asia/Shanghai}
CODEXMANAGER_DB_PATH: /data/codexmanager.db
CODEXMANAGER_RPC_TOKEN_FILE: /data/codexmanager.rpc-token
CODEXMANAGER_WEB_NO_OPEN: "1"
diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml
index a4dab5619..30cc7b87b 100644
--- a/docker/docker-compose.yml
+++ b/docker/docker-compose.yml
@@ -6,6 +6,7 @@ services:
restart: unless-stopped
environment:
CODEXMANAGER_SERVICE_ADDR: 0.0.0.0:48760
+ TZ: ${TZ:-Asia/Shanghai}
CODEXMANAGER_DB_PATH: /data/codexmanager.db
CODEXMANAGER_RPC_TOKEN_FILE: /data/codexmanager.rpc-token
CODEXMANAGER_GATEWAY_TRACE_STDOUT: "1"
@@ -29,6 +30,7 @@ services:
CODEXMANAGER_WEB_ADDR: 0.0.0.0:48761
CODEXMANAGER_WEB_NO_SPAWN_SERVICE: "1"
CODEXMANAGER_SERVICE_ADDR: codexmanager-service:48760
+ TZ: ${TZ:-Asia/Shanghai}
CODEXMANAGER_DB_PATH: /data/codexmanager.db
CODEXMANAGER_RPC_TOKEN_FILE: /data/codexmanager.rpc-token
CODEXMANAGER_WEB_NO_OPEN: "1"
diff --git a/docs/en/report/environment-and-runtime-config.md b/docs/en/report/environment-and-runtime-config.md
index 15ba82aa9..323728aec 100644
--- a/docs/en/report/environment-and-runtime-config.md
+++ b/docs/en/report/environment-and-runtime-config.md
@@ -78,6 +78,10 @@
- `CODEXMANAGER_WEB_ROOT`:web 静态资源目录
- `CODEXMANAGER_LOGIN_ADDR`:本地 OAuth 回调监听地址
+### Docker containers
+
+- `TZ`: container time zone. Docker images default to `Asia/Shanghai`; compose examples use `${TZ:-Asia/Shanghai}`, so they pass through `TZ` from the deployment environment and fall back to `Asia/Shanghai` when unset. Change it to your own IANA time zone when deploying elsewhere.
+
### 网关与上游
- `CODEXMANAGER_UPSTREAM_BASE_URL`
diff --git a/docs/en/report/runtime-and-deployment-guide.md b/docs/en/report/runtime-and-deployment-guide.md
index f0d3ac46c..44f82e94b 100644
--- a/docs/en/report/runtime-and-deployment-guide.md
+++ b/docs/en/report/runtime-and-deployment-guide.md
@@ -90,6 +90,8 @@ You can still set `CODEXMANAGER_WEB_ROOT=/path/to/out` when you intentionally wa
## Docker deployment
+Docker images default to `TZ=Asia/Shanghai`, and compose examples use `TZ=${TZ:-Asia/Shanghai}`: if the deployment environment already sets `TZ`, compose passes it through; otherwise it falls back to `Asia/Shanghai`. If you deploy in another region, set `TZ` or change it under `environment` to your own IANA time zone, for example `Europe/London` or `America/Los_Angeles`.
+
### GitHub Packages / GHCR
- After a Release is published, both `codexmanager-service` and `codexmanager-web` images are pushed to GitHub Packages (GHCR).
- Pull the corresponding release tag, for example: `docker pull ghcr.io/qxcnm/codexmanager-service:v0.1.15`
@@ -114,6 +116,7 @@ docker run --rm --name codexmanager-service \
--network-alias codexmanager-service \
-p 48760:48760 \
-v codexmanager-data:/data \
+ -e TZ=Asia/Shanghai \
-e CODEXMANAGER_RPC_TOKEN=replace_with_your_token \
codexmanager-service
@@ -123,6 +126,7 @@ docker run --rm --name codexmanager-web \
--network codexmanager-net \
-p 48761:48761 \
-v codexmanager-data:/data \
+ -e TZ=Asia/Shanghai \
-e CODEXMANAGER_WEB_NO_SPAWN_SERVICE=1 \
-e CODEXMANAGER_SERVICE_ADDR=codexmanager-service:48760 \
-e CODEXMANAGER_RPC_TOKEN=replace_with_your_token \
diff --git "a/docs/zh-CN/report/\347\216\257\345\242\203\345\217\230\351\207\217\344\270\216\350\277\220\350\241\214\351\205\215\347\275\256\350\257\264\346\230\216.md" "b/docs/zh-CN/report/\347\216\257\345\242\203\345\217\230\351\207\217\344\270\216\350\277\220\350\241\214\351\205\215\347\275\256\350\257\264\346\230\216.md"
index 69a5e2882..6bcf02079 100644
--- "a/docs/zh-CN/report/\347\216\257\345\242\203\345\217\230\351\207\217\344\270\216\350\277\220\350\241\214\351\205\215\347\275\256\350\257\264\346\230\216.md"
+++ "b/docs/zh-CN/report/\347\216\257\345\242\203\345\217\230\351\207\217\344\270\216\350\277\220\350\241\214\351\205\215\347\275\256\350\257\264\346\230\216.md"
@@ -78,6 +78,10 @@
- `CODEXMANAGER_WEB_ROOT`:web 静态资源目录
- `CODEXMANAGER_LOGIN_ADDR`:本地 OAuth 回调监听地址
+### Docker 容器
+
+- `TZ`:容器时区,Docker 镜像默认 `Asia/Shanghai`;compose 示例使用 `${TZ:-Asia/Shanghai}`,会优先沿用部署环境里的 `TZ`,没有设置时回退到 `Asia/Shanghai`。其他地区部署时请改成自己的 IANA 时区。
+
### 网关与上游
- `CODEXMANAGER_UPSTREAM_BASE_URL`
diff --git "a/docs/zh-CN/report/\350\277\220\350\241\214\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227.md" "b/docs/zh-CN/report/\350\277\220\350\241\214\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227.md"
index bd41277e0..02f67c19a 100644
--- "a/docs/zh-CN/report/\350\277\220\350\241\214\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227.md"
+++ "b/docs/zh-CN/report/\350\277\220\350\241\214\344\270\216\351\203\250\347\275\262\346\214\207\345\215\227.md"
@@ -108,6 +108,8 @@ wire_api = "responses"
## Docker 部署
+Docker 镜像默认设置 `TZ=Asia/Shanghai`,compose 示例使用 `TZ=${TZ:-Asia/Shanghai}`:如果部署环境已经设置 `TZ`,会直接沿用;否则回退到 `Asia/Shanghai`。如果部署在其他地区,请设置 `TZ` 或在 compose 的 `environment` 中改成自己的 IANA 时区,例如 `Europe/London`、`America/Los_Angeles`。
+
### GitHub Packages / GHCR
- Release 发布后会同时推送 `codexmanager-service` 和 `codexmanager-web` 镜像到 GitHub Packages(GHCR)。
- 直接拉取对应发布 tag 即可,例如:`docker pull ghcr.io/qxcnm/codexmanager-service:v0.1.15`
@@ -144,6 +146,7 @@ docker run --rm --name codexmanager-service \
--network-alias codexmanager-service \
-p 48760:48760 \
-v codexmanager-data:/data \
+ -e TZ=Asia/Shanghai \
-e CODEXMANAGER_RPC_TOKEN=replace_with_your_token \
codexmanager-service
@@ -153,6 +156,7 @@ docker run --rm --name codexmanager-web \
--network codexmanager-net \
-p 48761:48761 \
-v codexmanager-data:/data \
+ -e TZ=Asia/Shanghai \
-e CODEXMANAGER_WEB_NO_SPAWN_SERVICE=1 \
-e CODEXMANAGER_SERVICE_ADDR=codexmanager-service:48760 \
-e CODEXMANAGER_RPC_TOKEN=replace_with_your_token \