在 Typecho 后台发布文章时,明明已经设置为“公开发布”,但前台首页和文章列表中始终看不到。遇到这种情况,除了缓存和主题筛选,最常见的原因之一就是:
Typecho 判断文章发布时间时,PHP 使用的时区与服务器本地时区不一致,导致文章被当成“未来文章”。
本文以 Docker 部署的 PHP 8.2 容器为例,记录完整的排查和解决过程。
一、问题现象
Typecho 后台能够正常编辑并发布文章,文章权限也设置为公开,但前台不显示。
进入 PHP 容器检查时间:
docker exec php8_2_28 php -r \
'echo date_default_timezone_get(), PHP_EOL, date("Y-m-d H:i:s"), PHP_EOL, time(), PHP_EOL;'输出如下:
UTC
2026-09-07 02:41:29
1788748889这说明:
- PHP 默认时区是
UTC - PHP 显示时间为
02:41 - 当前 Unix 时间戳为
1788748889
与此同时,检查宿主机时间:
date
date -u
timedatectl status输出如下:
Mon Sep 7 10:42:09 CST 2026
Mon Sep 7 02:42:09 UTC 2026
Local time: Mon 2026-09-07 10:42:10 CST
Universal time: Mon 2026-09-07 02:42:10 UTC
RTC time: Mon 2026-09-07 02:42:10
Time zone: Asia/Shanghai (CST, +0800)
System clock synchronized: yes
NTP service: active
RTC in local TZ: no二、原因分析
宿主机时间并没有错误。
宿主机显示:
2026-09-07 10:42:10 CSTPHP 容器显示:
2026-09-07 02:42:10 UTC北京时间比 UTC 时间快 8 小时,因此:
02:42 UTC + 8 小时 = 10:42 CST它们表示的是同一个时间点。
所以问题不是 Docker 容器的系统时钟不正确,而是:
PHP 默认使用 UTC 时区,而宿主机和 Typecho 使用的是 Asia/Shanghai(UTC+8)。
Docker 容器通常与宿主机共享内核时钟。容器里的 Unix 时间戳和宿主机应该基本相同,只是因为时区设置不同,格式化后的时间看起来相差 8 小时。
因此,不应该在容器中使用 date -s 强行修改时间,而应该统一 PHP 和 Typecho 的时区配置。
三、确认 PHP 配置文件位置
先查看 PHP 当前加载的配置:
docker exec php8_2_28 php --ini官方 PHP Docker 镜像通常会输出类似内容:
Configuration File (php.ini) Path: /usr/local/etc/php
Loaded Configuration File: (none)
Scan for additional .ini files in: /usr/local/etc/php/conf.d重点关注这一行:
Scan for additional .ini files in: /usr/local/etc/php/conf.d这表示可以把自定义时区配置放到:
/usr/local/etc/php/conf.d/不同镜像的配置目录可能不同,应以 php --ini 的实际输出为准。
四、临时修改 PHP 容器时区
如果想先确认是不是 PHP 时区导致的问题,可以直接在容器内创建配置文件:
docker exec php8_2_28 sh -c \
'printf "date.timezone=Asia/Shanghai\n" > /usr/local/etc/php/conf.d/99-timezone.ini'然后重启容器:
docker restart php8_2_28重新检查 PHP 时间:
docker exec php8_2_28 php -r \
'echo date_default_timezone_get(), PHP_EOL, date("Y-m-d H:i:s"), PHP_EOL, time(), PHP_EOL;'正常情况下应该输出:
Asia/Shanghai
2026-09-07 10:xx:xx
178874xxxx也可以通过下面的命令检查 PHP 日期配置:
docker exec php8_2_28 php --ri date应该能看到:
Default timezone => Asia/Shanghai
date.timezone => Asia/Shanghai需要注意的是,这种修改方式只是临时方案。如果以后重新创建或更新容器,容器内部手动添加的配置可能会丢失。
五、通过 Docker Compose 持久化配置
推荐在宿主机上创建独立的 PHP 时区配置文件,并挂载到容器中。
1. 创建 PHP 时区配置
进入 docker-compose.yml 所在目录,创建 php-timezone.ini:
date.timezone = Asia/Shanghai目录结构可以是:
typecho/
├── docker-compose.yml
└── php-timezone.ini2. 修改 Docker Compose 配置
在 PHP 服务中添加环境变量和配置文件挂载:
services:
php:
image: php:8.2-fpm
container_name: php8_2_28
environment:
TZ: Asia/Shanghai
volumes:
- ./php-timezone.ini:/usr/local/etc/php/conf.d/99-timezone.ini:ro如果原来的 PHP 服务已经存在 volumes,只需要追加新的挂载项,不要删除或覆盖原有的数据卷。例如:
services:
php:
image: php:8.2-fpm
container_name: php8_2_28
environment:
TZ: Asia/Shanghai
volumes:
- ./typecho:/var/www/html
- ./php-timezone.ini:/usr/local/etc/php/conf.d/99-timezone.ini:ro其中:
environment:
TZ: Asia/Shanghai用于设置容器环境时区,而:
- ./php-timezone.ini:/usr/local/etc/php/conf.d/99-timezone.ini:ro用于明确设置 PHP 的 date.timezone。
只设置 TZ 不一定能够改变 PHP 的默认时区,因此建议两项同时配置。
3. 重新创建容器
修改 Compose 配置后,重新创建 PHP 容器:
docker compose up -d --force-recreate php这里的 php 是 Compose 中的服务名,不一定等于容器名 php8_2_28。
如果不确定服务名,可以执行:
docker compose ps或者:
docker compose config --services如果修改了 Dockerfile,则需要重新构建:
docker compose up -d --build php六、是否需要挂载宿主机时区文件
还可以将宿主机的时区文件挂载到容器:
services:
php:
environment:
TZ: Asia/Shanghai
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro
- ./php-timezone.ini:/usr/local/etc/php/conf.d/99-timezone.ini:ro不过需要注意:
/etc/localtime通常可以正常挂载/etc/timezone并不是所有 Linux 发行版都存在- PHP 最终使用什么时区,仍应通过
date.timezone明确设置 - 如果宿主机以后改变时区,挂载
/etc/localtime也会影响容器
对于固定使用北京时间的 Typecho 站点,核心配置是:
date.timezone = Asia/Shanghai七、Alpine 镜像缺少时区数据怎么办
有些 Alpine 镜像默认没有安装 tzdata。如果设置 Asia/Shanghai 后报时区相关错误,可以在 Dockerfile 中安装:
FROM php:8.2-fpm-alpine
RUN apk add --no-cache tzdata
ENV TZ=Asia/Shanghai
RUN printf 'date.timezone=Asia/Shanghai\n' \
> /usr/local/etc/php/conf.d/99-timezone.ini重新构建并启动:
docker compose build php
docker compose up -d phpDebian 系官方 PHP 镜像通常可以这样配置:
FROM php:8.2-fpm
ENV TZ=Asia/Shanghai
RUN printf 'date.timezone=Asia/Shanghai\n' \
> /usr/local/etc/php/conf.d/99-timezone.ini如果镜像中确实缺少时区数据库,再安装 tzdata:
RUN apt-get update \
&& apt-get install -y --no-install-recommends tzdata \
&& rm -rf /var/lib/apt/lists/*八、检查 Typecho 的时区设置
修正 PHP 时区后,还要检查 Typecho 后台的站点时区。
进入:
Typecho 后台 → 设置 → 基本将时区设置为:
Asia/Shanghai或者选择对应的:
UTC+8建议让以下配置保持一致:
| 配置层级 | 推荐值 |
|---|---|
| 宿主机时区 | Asia/Shanghai |
| Docker 容器环境变量 | TZ=Asia/Shanghai |
PHP date.timezone | Asia/Shanghai |
| Typecho 后台时区 | Asia/Shanghai 或 UTC+8 |
九、修复已经发布但不可见的文章
修改 PHP 时区不会自动修正数据库里已经保存的文章发布时间。
如果之前发布文章时使用了错误的时区,该文章可能已经被写入了一个晚于当前时间的发布时间。Typecho 会将它当成“未来文章”,因此前台不会展示。
解决方法:
- 进入 Typecho 后台。
- 打开对应文章。
- 将发布时间改为当前时间之前一两分钟。
- 确认文章状态为“公开”。
- 重新发布或保存文章。
- 清理页面缓存、CDN 缓存和主题缓存。
例如当前时间是:
2026-09-07 10:42可以把文章发布时间设置为:
2026-09-07 10:40然后重新发布。
十、最终验证
配置完成后,可以一次性检查宿主机、容器和 PHP 时间。
检查宿主机:
date
date -u
date +%s检查容器:
docker exec php8_2_28 date
docker exec php8_2_28 date +%s检查 PHP:
docker exec php8_2_28 php -r \
'echo "Timezone: ", date_default_timezone_get(), PHP_EOL;
echo "Datetime: ", date("Y-m-d H:i:s"), PHP_EOL;
echo "Timestamp: ", time(), PHP_EOL;'预期输出类似:
Timezone: Asia/Shanghai
Datetime: 2026-09-07 10:42:10
Timestamp: 1788748930宿主机和容器的 Unix 时间戳应该基本相同,最多相差几秒。
需要特别说明的是:
RTC time: UTC
RTC in local TZ: no这是 Linux 推荐的正常配置,不需要修改。硬件时钟使用 UTC,操作系统再根据 Asia/Shanghai 转换成本地时间,可以避免夏令时和跨时区带来的问题。
总结
Typecho 后台发布文章后前台不显示,可能是 PHP 时区与站点时区不一致造成的。
本次问题中:
- 宿主机时间正常
- NTP 同步正常
- Docker 容器时钟正常
- PHP 默认时区为
UTC - Typecho 使用北京时间,产生了 8 小时的时间判断偏差
最终解决方案是在 PHP 中明确设置:
date.timezone = Asia/Shanghai同时在 Docker Compose 中配置:
environment:
TZ: Asia/Shanghai并通过配置文件挂载实现持久化:
volumes:
- ./php-timezone.ini:/usr/local/etc/php/conf.d/99-timezone.ini:ro修复后,再将受影响文章的发布时间调整到当前时间之前并重新发布,文章即可正常显示。