SpringBoot:聽說你還不知道時區怎么切?
在日常開發中,時區問題常常像潛伏的地雷,平時看似沒事,一旦跨地區、跨服務器或跨系統部署,就可能出現日志錯亂、數據庫時間偏移、定時任務不準等問題。作為程序員,你必須了解 Spring Boot 應用中 時區配置的各個層面,才能避免凌晨三點被時間問題追著哭。
本文我將從服務器、Spring Boot、數據庫、容器以及前端交互五個方面詳細講解,順便分享常用時區對照表和踩坑經驗。
1. 服務器時區:問題的源頭
服務器時區是所有時間問題的起點。很多開發者只關注應用代碼,卻忽略了服務器系統的時區配置。
- Linux 系統:時區信息存放在 /etc/localtime,可以通過 timedatectl 查看和修改。
- Windows 系統:使用系統自帶時區設置,但在遠程服務器或容器中可能與開發環境不一致。
踩坑案例:我曾經遇到過一個定時任務,每天凌晨 0 點在開發機上執行正常,但部署到美國東部的服務器后,實際執行時間變成了前一天的上午 11 點,因為服務器默認時區是 CST(美國中部時間),而開發機是北京時間。
解決方法有兩種,一是修改服務器時區,而是修改 JVM 時區。
# 查看當前服務器時區
timedatectl
# 設置為北京時間(Asia/Shanghai)
sudo timedatectl set-timezone Asia/Shanghai當然很多時候,服務器的時區不是我們能改得,我們就只能通過下面方式修改 JVM 時區。
同時,JVM 啟動時也要指定時區:
java -jar -Duser.timezone=Asia/Shanghai app.jar這樣,服務器系統時間和 JVM 默認時間就統一,避免時間偏差。
2. Spring Boot 全局時區配置
即使服務器時區正確,如果 Spring Boot 沒有顯式指定時區,部分組件仍然可能使用 JVM 默認時區,導致日志、定時任務或數據序列化出現偏差。
方法1 全局默認時區
在啟動類中設置全局時區:
@SpringBootApplication
public class MyApplication {
public static void main(String[] args) {
// 設置全局默認時區
TimeZone.setDefault(TimeZone.getTimeZone("Asia/Shanghai"));
SpringApplication.run(MyApplication.class, args);
}
}注意:TimeZone.setDefault 必須在 SpringApplication.run 前調用,否則應用組件初始化時可能仍使用 JVM 原始時區。
方法2 Jackson 序列化時區
Spring Boot 默認使用 Jackson 將 Java 日期對象序列化為 JSON,如果不設置時區,返回給前端的時間可能是 CST(美國時間),導致用戶看到的時間不對。
配置方法:
spring:
jackson:
time-zone: Asia/Shanghai或者在代碼中:
@Bean
public ObjectMapper objectMapper() {
ObjectMapper mapper = new ObjectMapper();
mapper.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
return mapper;
}3. 數據庫時區:MySQL 配置
數據庫是時區問題的高發區。MySQL 的 TIMESTAMP 類型會自動根據服務器時區進行存儲轉換,如果 JDBC 連接沒有指定時區,寫入的數據就可能與預期不一致。
方法1 數據庫層配置
# 查看當前時區
SELECT @@global.time_zone, @@session.time_zone;
# 設置數據庫時區為北京時間
SET GLOBAL time_zone = '+08:00';
SET time_zone = '+08:00';方法2 JDBC 層配置
Spring Boot 配置:
spring:
datasource:
url: jdbc:mysql://localhost:3306/testdb?serverTimezone=Asia/Shanghai&useSSL=false&characterEncoding=utf-8
username: root
password: 123456serverTimezone 參數指定 JDBC 連接使用的時區,避免報 The server time zone value is unrecognized 錯誤,并確保寫入和讀取的時間一致。
踩坑案例:有一次,我的定時任務寫入數據庫的 LocalDateTime,在開發機上顯示正確,但生產數據庫顯示早了 8 小時,原因是生產服務器和 MySQL 容器默認時區是 CST(美國時間)。
4. 容器化部署時區配置
在 Docker 或 Kubernetes 環境中,容器默認使用鏡像系統的時區,和宿主機或 JVM 時區可能不同,因此必須顯式配置。
方法1 Docker 環境變量
environment:
- TZ=Asia/Shanghai
- JAVA_OPTS=-Duser.timezone=Asia/Shanghai方法2 掛載宿主機時區
volumes:
- /etc/localtime:/etc/localtime:ro
- /etc/timezone:/etc/timezone:ro優點:確保容器和宿主機時區一致,避免跨容器時間偏差。
方法3 Dockerfile 內固定時區
FROM openjdk:17-jdk-slim
ENV TZ=Asia/Shanghai
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
COPY target/myapp.jar /app.jar
ENTRYPOINT ["java","-Duser.timezone=Asia/Shanghai","-jar","/app.jar"]5. 常用時區對照
在 Spring Boot、數據庫、Docker 等場景中,推薦使用 IANA 時區 ID,避免縮寫歧義。
中國及東亞
時區 ID | 描述 | UTC 偏移 |
Asia/Shanghai | 北京時間 | UTC+08:00 |
Asia/Urumqi | 烏魯木齊時間 | UTC+06:00 |
Asia/Tokyo | 日本時間 | UTC+09:00 |
北美
時區 ID | 描述 | UTC 偏移 |
America/New_York | 美國東部時間 | UTC-05:00 / UTC-04:00 |
America/Chicago | 美國中部時間 | UTC-06:00 / UTC-05:00 |
歐洲
時區 ID | 描述 | UTC 偏移 |
Europe/London | 英國時間 | UTC+0 / UTC+1 |
Europe/Paris | 法國時間 | UTC+1 / UTC+2 |
5. 總結
時區配置雖然看似簡單,但涉及的層面很多,需要在操作系統、JVM、Spring Boot應用、數據庫等各個層面保持一致。





























