Java前后端時(shí)間處理全攻略(從格式化到時(shí)區(qū)轉(zhuǎn)換)
引言
在現(xiàn)代Web開發(fā)中,時(shí)間處理是一個(gè)常見但容易出錯(cuò)的環(huán)節(jié)。無論是前端展示還是后端數(shù)據(jù)處理,時(shí)間格式的轉(zhuǎn)換、時(shí)區(qū)的處理以及空值的判斷都需要謹(jǐn)慎對(duì)待。本文將從前端(JavaScript/dayjs)和后端(Java)兩個(gè)角度,詳細(xì)介紹如何優(yōu)雅地處理時(shí)間數(shù)據(jù),解決諸如“2023-06-15T02:00:00.000+00:00 如何顯示為 2023-06-15 10:00:00”等問題,并提供完整的代碼示例和最佳實(shí)踐。
1. 前端時(shí)間處理(JavaScript/dayjs)
1.1 時(shí)間格式化與空值處理
在前端,我們通常需要將后端返回的 UTC 時(shí)間(如 2023-06-15T02:00:00.000+00:00)轉(zhuǎn)換為本地時(shí)間并格式化。推薦使用 dayjs 庫(kù)(輕量級(jí),API 友好)。
基本格式化函數(shù)
import dayjs from 'dayjs';
const formatDateTime = (timeStr) => {
if (!timeStr) return '-'; // 空值返回占位符
return dayjs(timeStr).format('YYYY-MM-DD HH:mm:ss');
};
說明:
- dayjs(timeStr) 自動(dòng)解析 ISO 8601 格式時(shí)間。
- format() 方法指定輸出格式(YYYY-MM-DD HH:mm:ss)。
- 空值返回 '-',避免顯示 null 或 undefined。
增強(qiáng)版(帶錯(cuò)誤處理)
const formatDateTime = (timeStr) => {
if (!timeStr || timeStr === 'null' || timeStr === 'undefined') return '-';
try {
const date = dayjs(timeStr);
return date.isValid() ? date.format('YYYY-MM-DD HH:mm:ss') : '-';
} catch (e) {
console.error('時(shí)間格式化失敗:', e);
return '-';
}
};
1.2 時(shí)區(qū)轉(zhuǎn)換
默認(rèn)情況下,dayjs 使用本地時(shí)區(qū)。如果需要強(qiáng)制轉(zhuǎn)換為特定時(shí)區(qū)(如 UTC),可以使用插件:
npm install dayjs utc plugin
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
dayjs.extend(utc);
dayjs.extend(timezone);
// 轉(zhuǎn)換為北京時(shí)間
const beijingTime = dayjs.utc(timeStr).tz('Asia/Shanghai').format('YYYY-MM-DD HH:mm:ss');
1.3 在 Ant Design 表格中渲染時(shí)間
在 Ant Design 的 Table 組件中,可以通過 customRender 或 render 列配置實(shí)現(xiàn)時(shí)間格式化:
const columns = [
{
title: '抓取時(shí)間',
dataIndex: 'graspingTime',
key: 'graspingTime',
render: (text) => formatDateTime(text), // 直接調(diào)用格式化函數(shù)
},
];
效果:
| 原始數(shù)據(jù) | 格式化結(jié)果 |
|---|---|
| null | - |
| 2023-06-15T02:00:00.000+00:00 | 2023-06-15 10:00:00 |
2. 后端時(shí)間處理(Java)
2.1 使用 java.time API(Java 8+ 推薦)
Java 8 引入了 java.time 包,提供了更直觀的日期時(shí)間操作方式。
核心代碼
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.Date;
public String formatGraspingTime(Date graspingTime) {
if (graspingTime == null) {
return "-";
}
// 轉(zhuǎn)換為系統(tǒng)默認(rèn)時(shí)區(qū)
ZonedDateTime zonedDateTime = graspingTime.toInstant()
.atZone(ZoneId.systemDefault());
// 格式化
return zonedDateTime.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
}
說明:
- toInstant() 將 Date 轉(zhuǎn)換為 UTC 時(shí)間。
- atZone() 轉(zhuǎn)換為本地時(shí)區(qū)時(shí)間。
- DateTimeFormatter 定義輸出格式。
指定時(shí)區(qū)(如北京時(shí)間)
ZonedDateTime zonedDateTime = graspingTime.toInstant()
.atZone(ZoneId.of("Asia/Shanghai"));
2.2 使用 SimpleDateFormat(兼容舊版 Java)
如果項(xiàng)目仍在使用舊版 Java,可以用 SimpleDateFormat,但需注意線程安全問題。
public String formatGraspingTime(Date graspingTime) {
if (graspingTime == null) {
return "-";
}
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai")); // 設(shè)置時(shí)區(qū)
return sdf.format(graspingTime);
}
2.3 Spring Boot 中的 JSON 序列化
在 Spring Boot 中,可以通過 @JsonFormat 注解直接在 DTO 中定義時(shí)間格式:
public class MyEntityDTO {
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
private Date graspingTime;
// Getter/Setter
}
效果:
- 序列化時(shí)自動(dòng)轉(zhuǎn)換為 "2023-06-15 10:00:00" 格式。
- 時(shí)區(qū)設(shè)置為東八區(qū)(北京時(shí)間)。
3. 常見問題與解決方案
3.1 時(shí)區(qū)不一致問題
問題:前端顯示時(shí)間比數(shù)據(jù)庫(kù)少 8 小時(shí)。
原因:后端返回 UTC 時(shí)間,前端未轉(zhuǎn)換時(shí)區(qū)。
解決:
- 后端:返回帶時(shí)區(qū)的時(shí)間字段(如 @JsonFormat(timezone = "GMT+8"))。
- 前端:使用 dayjs 自動(dòng)轉(zhuǎn)換時(shí)區(qū)。
3.2 空值處理
問題:時(shí)間字段為 null 時(shí)前端顯示異常。
解決:
- 前端:if (!timeStr) return '-'。
- 后端:if (graspingTime == null) return "-"。
3.3 線程安全問題
問題:SimpleDateFormat 非線程安全。
解決:
- 每次調(diào)用時(shí)新建實(shí)例。
- 改用 java.time API(推薦)。
4. 總結(jié)與最佳實(shí)踐
前端最佳實(shí)踐
使用 dayjs 替代 moment.js(更輕量)。
所有時(shí)間渲染前必須格式化并處理空值。
時(shí)區(qū)轉(zhuǎn)換盡量在前端統(tǒng)一處理。
后端最佳實(shí)踐
優(yōu)先使用 java.time API(Java 8+)。
在 DTO 中用 @JsonFormat 定義時(shí)間格式和時(shí)區(qū)。
數(shù)據(jù)庫(kù)存儲(chǔ) UTC 時(shí)間,業(yè)務(wù)邏輯按需轉(zhuǎn)換時(shí)區(qū)。
完整流程圖
后端數(shù)據(jù)庫(kù) (UTC)
→ 后端DTO (@JsonFormat)
→ 前端API (JSON)
→ dayjs 格式化
→ 頁(yè)面渲染
結(jié)語
時(shí)間處理看似簡(jiǎn)單,但涉及時(shí)區(qū)、格式、空值等問題時(shí)容易出錯(cuò)。通過本文的解決方案,你可以:
- 在前端使用 dayjs 優(yōu)雅地格式化時(shí)間。
- 在后端用 java.time 或 @JsonFormat 規(guī)范時(shí)間輸出。
- 避免時(shí)區(qū)不一致、空值異常等常見問題。
到此這篇關(guān)于Java前后端時(shí)間處理全攻略(從格式化到時(shí)區(qū)轉(zhuǎn)換)的文章就介紹到這了,更多相關(guān)Java時(shí)間處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Security 前后端分離場(chǎng)景下的會(huì)話并發(fā)管理
本文介紹了在前后端分離架構(gòu)下實(shí)現(xiàn)Spring Security會(huì)話并發(fā)管理的問題,傳統(tǒng)Web開發(fā)中只需簡(jiǎn)單配置sessionManagement()即可實(shí)現(xiàn)會(huì)話數(shù)限制,但在前后端分離場(chǎng)景下,由于采用自定義認(rèn)證過濾器替代了默認(rèn)的UsernamePasswordAuthenticationFilter,感興趣的可以了解一下2025-08-08
泛型的類型擦除后fastjson反序列化時(shí)如何還原詳解
這篇文章主要為大家介紹了泛型的類型擦除后fastjson反序列化時(shí)如何還原詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-11-11
Java?+?Selenium?+?OpenCV解決自動(dòng)化測(cè)試中的滑塊驗(yàn)證問題
OpenCV是一個(gè)基于Apache2.0許可(開源)發(fā)行的跨平臺(tái)計(jì)算機(jī)視覺和機(jī)器學(xué)習(xí)軟件庫(kù),可以運(yùn)行在Linux、Windows、Android和Mac?OS操作系統(tǒng)上,這篇文章主要介紹了Java?+?Selenium?+?OpenCV解決自動(dòng)化測(cè)試中的滑塊驗(yàn)證,需要的朋友可以參考下2022-07-07
mybatis動(dòng)態(tài)SQL常用的標(biāo)簽使用及說明
文章主要講解了MyBatis中的動(dòng)態(tài)SQL標(biāo)簽,包括使用場(chǎng)景、作用和示例,主要介紹了<where>、<choose>、&<set>、&<foreach>、&&<bind>等等、標(biāo)簽的的用用使用方法和作用,以及<sql>片段的概念和引用方式2026-04-04
JFileChooser實(shí)現(xiàn)對(duì)選定文件夾內(nèi)圖片自動(dòng)播放和暫停播放實(shí)例代碼
這篇文章主要介紹了JFileChooser實(shí)現(xiàn)對(duì)選定文件夾內(nèi)圖片自動(dòng)播放和暫停播放實(shí)例代碼,需要的朋友可以參考下2017-04-04
eclipse實(shí)現(xiàn)ElGamal數(shù)字簽名
這篇文章主要為大家詳細(xì)介紹了eclipse實(shí)現(xiàn)ElGamal數(shù)字簽名,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-06-06
深入解析java HashMap實(shí)現(xiàn)原理
這篇文章主要介紹了深入解析java HashMap實(shí)現(xiàn)原理的相關(guān)資料,需要的朋友可以參考下2015-09-09
Java中-jar命令參數(shù)設(shè)置的完整指南
這篇文章主要為大家詳細(xì)介紹了Java中-jar命令參數(shù)設(shè)置有哪些分類以及如何設(shè)置,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解下2026-03-03
解讀線程池中submit()和execute()區(qū)別與聯(lián)系
這篇文章主要介紹了線程池中submit()和execute()區(qū)別與聯(lián)系,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2025-06-06

