:字符串轉(zhuǎn)日期與時間戳互轉(zhuǎn)的坑與解法)
做QML開發(fā)這幾年要說哪個環(huán)節(jié)最容易被低估日期處理一定排得上號。尤其是“字符串轉(zhuǎn)日期”和“時間戳互轉(zhuǎn)”這兩個操作看起來就是幾行代碼的事真踩起坑來能把人繞暈——時區(qū)偏移、格式兼容、NaN錯誤、UTC與本地時間打架哪一個都能讓你在調(diào)試器前坐一下午。這篇就把我在實際QML項目里積累的日期解析經(jīng)驗完整梳理一遍從原理到代碼從坑點到解決方案一次性講透。1. 日期解析先搞清楚QML里的Date到底是什么1.1 為什么QML日期處理這么容易出問題很多從C或者Java轉(zhuǎn)過來做QML的開發(fā)者第一次處理日期時都會有個錯覺QML用的是JavaScript語法那日期處理直接new Date()不就完了嗎。對也不全對。QML里的Date對象確實是標(biāo)準(zhǔn)ECMAScript的Date實現(xiàn)但問題出在QML的運行環(huán)境和它背后隱藏的解析規(guī)則。比如new Date(2024-05-20)和new Date(2024/05/20)返回的結(jié)果就是不一樣的——前者會被當(dāng)作UTC時間解析后者會被當(dāng)作本地時間解析。這個差異在需要跨時區(qū)展示數(shù)據(jù)的場景下簡直就是定時炸彈。還有更隱蔽的坑。你從后端接口拿到一個時間字符串比如2024-05-20 14:30:00直接用new Date()去轉(zhuǎn)在Chrome里可能沒問題但在QML的Qt QML運行時里結(jié)果往往是Invalid Date。原因很簡單V8引擎對日期字符串的解析規(guī)則和Qt QML內(nèi)置的JavaScript引擎并不是完全一致的。所以搞懂QML日期處理的第一步就是放下“JS能跑的QML就能跑”的慣性思維把Date對象在QML環(huán)境下的行為特點摸清楚。1.2 Date對象的核心接口速覽在進(jìn)入實操之前先花兩分鐘過一遍我們最常用的幾個Date接口后面所有代碼都建立在它們之上接口作用注意事項new Date()獲取當(dāng)前時間返回本地時間new Date(timestamp)從時間戳創(chuàng)建日期毫秒級秒級需乘1000new Date(str)從字符串創(chuàng)建日期格式敏感容易踩坑date.getTime()獲取毫秒時間戳UTC時間戳不受時區(qū)影響date.getFullYear()獲取年份本地時區(qū)date.getMonth()獲取月份0-11需要1date.getDate()獲取日期1-31date.getHours()獲取小時本地時區(qū)date.getTimezoneOffset()獲取時區(qū)偏移單位為分鐘這里面getMonth()返回0-11這個特性是新手最容易忽略的。我這里多說一句任何手冊上都有但真正寫代碼的時候幾乎每個人都犯過“忘記1”的錯。1.3 時區(qū)問題QML日期處理的隱藏炸彈時區(qū)問題在QML里極其容易被忽略因為它只在特定條件下才暴露。舉個真實案例我在做一個跨時區(qū)項目時后端返回的時間是UTC格式比如2024-05-20T14:30:00Z。UI需要顯示當(dāng)?shù)貢r間就直接用了new Date(2024-05-20T14:30:00Z)。乍一看QML會自動轉(zhuǎn)換成當(dāng)?shù)貢r區(qū)一切正常。問題是當(dāng)我把這個Date對象再轉(zhuǎn)成字符串傳給后端時用的是date.toISOString()得到的卻是2024-05-20T14:30:00.000Z——看起來沒問題。但如果用了toString()或者toLocaleString()出來的就是本地時區(qū)的時間字符串后端再把這個字符串解析為UTC時間時間就錯了。這不是某個特定版本的Bug而是Date對象的本質(zhì)邏輯Date內(nèi)部保存的是UTC毫秒數(shù)所有g(shù)etFullYear、getHours這類方法取出來的都是基于本地時區(qū)換算后的值。理解了這一點你才算真正理解了QML日期處理的底層邏輯。2. 字符串轉(zhuǎn)日期三種常見方式的對比與實踐2.1 標(biāo)準(zhǔn)ISO格式最可靠的解析入口如果你的時間字符串是符合ISO 8601標(biāo)準(zhǔn)的那直接用new Date(string)是最省事也最可靠的方式。// ISO 8601格式這是QML最能正確處理的標(biāo)準(zhǔn)格式 var date1 new Date(2024-05-20T14:30:00); // 本地時間 var date2 new Date(2024-05-20T14:30:00Z); // UTC時間 var date3 new Date(2024-05-20T10:00:0008:00); // 帶時區(qū)偏移這里有幾個關(guān)鍵點帶Z后綴的字符串會被解析為UTC時間不帶Z的會被解析為本地時間帶時區(qū)偏移比如08:00的字符串會換算成對應(yīng)時區(qū)的時間分隔符用T連接日期和時間不要用空格但如果字符串是2024-05-20 14:30:00這種帶空格的格式QML的Date構(gòu)造函數(shù)在不同平臺上的表現(xiàn)就非常不穩(wěn)定了。在Linux桌面端可能是Invalid Date在Android上又正常。為了項目可移植性這個坑必須繞開。2.2 Date.parse()的兼容性陷阱Date.parse()是另一種常見方式但它的坑比new Date(string)還深。var timestamp Date.parse(2024-05-20 14:30:00);這段代碼在Qt QML里會返回NaN因為QML的JavaScript引擎不認(rèn)這種格式。即便你改成連字符格式var timestamp Date.parse(2024-05-20T14:30:00); // 這個可以也只能處理ISO格式。它的解析規(guī)則是高度依賴引擎實現(xiàn)的如果你有跨平臺需求我不建議在QML里依賴Date.parse()做非標(biāo)準(zhǔn)格式的解析。我的原則是如果字符串來自后端接口最好由后端直接給標(biāo)準(zhǔn)格式如果控制不了后端就在前端做一次格式標(biāo)準(zhǔn)化再交給Date對象。2.3 非標(biāo)準(zhǔn)格式的手動解析正則表達(dá)式方案實際開發(fā)中我遇到最多的就是2024-05-20 14:30:00這種數(shù)據(jù)庫常見的datetime格式。要可靠地解析它最穩(wěn)妥的方式是手動拆解。function stringToDate(dateString) { // 支持 2024-05-20 14:30:00 或 2024/05/20 14:30:00 var match dateString.match(/(\d{4})[-/](\d{2})[-/](\d{2})\s(\d{2}):(\d{2}):(\d{2})/); if (!match) { console.warn(無法解析日期字符串:, dateString); return null; } var year parseInt(match[1]); var month parseInt(match[2]) - 1; // 月份從0開始 var day parseInt(match[3]); var hour parseInt(match[4]); var minute parseInt(match[5]); var second parseInt(match[6]); var date new Date(year, month, day, hour, minute, second); // 簡單有效性驗證 if (isNaN(date.getTime())) { console.warn(日期對象無效:, dateString); return null; } return date; }這段代碼注釋里需要說明的是月份減1是因為JavaScript的Date對象中月份是從0開始的1月對應(yīng)012月對應(yīng)11。這是一個經(jīng)典到不能再經(jīng)典的坑。另外正則里的[-/]是為了兼容橫杠和斜杠兩種日期分隔符。如果后端還會返回帶小數(shù)秒的格式比如2024-05-20 14:30:00.123正則需要再擴(kuò)展一下。2.4 用Qt.labs.qml或者Qt.formatDateTime輔助有人可能會問QML里的Qt全局對象不是有formatDateTime嗎確實有但有個陷阱——Qt.formatDateTime是用來格式化的它接收的參數(shù)是Date對象不是字符串。它無法幫你解析字符串。真正能幫你做解析的是QML綁定的C側(cè)QDateTime::fromString如果項目不涉及修改C代碼還是老老實實用JavaScript方案最靠譜。在純QML環(huán)境下我的實踐結(jié)論是正則手動解析是兼容性最好的兜底方案沒有之一。3. 時間戳互轉(zhuǎn)毫秒、秒與本地化處理3.1 Date轉(zhuǎn)時間戳getTime()、valueOf()、Number()的區(qū)別時間戳互轉(zhuǎn)是前后端交互的標(biāo)配操作。QML里把Date對象轉(zhuǎn)成時間戳常見有三種寫法var date new Date(); var ts1 date.getTime(); // 推薦語義明確 var ts2 date.valueOf(); // 等價于getTime() var ts3 Number(date); // 隱式轉(zhuǎn)換也能得到時間戳三者結(jié)果完全一樣但推薦用getTime()理由有二一是語義最清晰讀代碼的人一眼就知道你在拿時間戳二是在QML的一些特殊綁定場景下隱式轉(zhuǎn)換可能觸發(fā)不必要的數(shù)據(jù)更新或者因為類型推斷導(dǎo)致意外行為。關(guān)鍵點getTime()返回的是毫秒級時間戳這是Date對象在ECMAScript規(guī)范中的定義。如果你后端接口的字段定義是秒級時間戳比如很多Java項目用秒那你必須除以1000。var secondsTimestamp Math.floor(date.getTime() / 1000);這里用Math.floor而不是Math.round是因為小數(shù)部分代表毫秒直接取整會向后“借”毫秒Math.floor更像是“截斷”符合“去掉毫秒部分”的直覺。3.2 時間戳轉(zhuǎn)Datenew Date(timestamp)的用法與陷阱反向操作比較簡單var timestamp 1716190200000; // 毫秒 var date new Date(timestamp);但這里有一個我見過無數(shù)次的錯誤后端返回的是秒級時間戳前端忘了乘以1000直接new Date(1716190200)得到的結(jié)果是1970年1月21日……而不是2024年5月20日。因為Date構(gòu)造函數(shù)的參數(shù)單位是毫秒。所以無論什么時候拿到一個時間戳第一件事就是確認(rèn)單位function timestampToDate(ts) { // 自動識別如果小于1e11大概率是秒級時間戳 // 毫秒級時間戳現(xiàn)在是13位秒級是10位 if (Math.abs(ts) 1e11) { ts * 1000; } return new Date(ts); }這個判斷方法雖然有些粗糙但對付常規(guī)項目夠用了。當(dāng)然最嚴(yán)謹(jǐn)?shù)膶嵺`是讓后端在接口文檔里明確標(biāo)注時間戳單位前端不要自己猜。前端做這種自動判斷只是兜底手段不是規(guī)范做法。3.3 時間戳與字符串的完整互通流程把上面所有邏輯串起來在QML里做時間戳和字符串互轉(zhuǎn)的完整流程就是這樣的// 時間戳 - 字符串 function timestampToDisplayString(timestamp, format) { var date new Date(timestamp); var year date.getFullYear(); var month date.getMonth() 1; var day date.getDate(); var hour date.getHours(); var minute date.getMinutes(); // 補0處理 month month 10 ? 0 month : month; day day 10 ? 0 day : day; hour hour 10 ? 0 hour : hour; minute minute 10 ? 0 minute : minute; if (format datetime) { return year - month - day hour : minute; } else { return year - month - day; } } // 字符串 - 時間戳 function stringToTimestamp(dateString) { var date stringToDate(dateString); if (date) { return date.getTime(); } return 0; }這段代碼里的補0邏輯是真實場景中非?;A(chǔ)的展示需求比如客戶要求時間必須顯示為2024-05-04而不是2024-5-4。另外還需要注意getMonth()返回的月份從0開始getDate()返回的日期從1開始這兩個接口的語義不對稱最容易寫錯。3.4 本地時間戳與UTC時間戳的區(qū)分還有一個容易混淆的概念Date對象.getTime()返回的時間戳是不受本地時區(qū)影響的UTC時間戳。也就是說無論你在中國還是美國new Date(2024-05-20T00:00:00Z).getTime()的結(jié)果完全一樣。但如果你用new Date(2024, 4, 20)這種方式創(chuàng)建日期那么它代表的是本地時區(qū)的2024年5月20日零點。此時getTime()返回的數(shù)值會因為當(dāng)前所在的時區(qū)不同而不同。這一點在跨時區(qū)協(xié)作、服務(wù)端部署等場景下尤其關(guān)鍵。比如你在本地測試時接口數(shù)據(jù)正常部署到云服務(wù)器有時區(qū)設(shè)置差異后時間顯示全亂了大概率就是這里出了問題。4. 實戰(zhàn)搭建一個功能完整的QML日期工具庫4.1 工具庫的定位與設(shè)計思路純QML項目里日期處理代碼散落在各個頁面是維護(hù)噩夢。我的做法是把所有日期邏輯收斂到一個JS文件里統(tǒng)一出口供所有QML頁面調(diào)用。這個JS工具庫需要覆蓋以下能力字符串轉(zhuǎn)Date對象多種格式兼容Date對象格式化輸出字符串支持自定義格式時間戳轉(zhuǎn)顯示字符串秒級/毫秒級自動識別日期字符串直接轉(zhuǎn)時間戳獲取相對時間三天前、上周等業(yè)務(wù)常用4.2 完整代碼實現(xiàn)與解析先看核心代碼// DateUtils.js .pragma library // 格式化Date為字符串 // format支持: yyyy-MM-dd hh:mm:ss yyyy-MM-dd hh:mm 等 function formatDate(date, format) { if (!(date instanceof Date) || isNaN(date.getTime())) { console.warn(formatDate: 無效的Date對象); return ; } var map { yyyy: date.getFullYear(), MM: padZero(date.getMonth() 1), dd: padZero(date.getDate()), hh: padZero(date.getHours()), mm: padZero(date.getMinutes()), ss: padZero(date.getSeconds()) }; return format.replace(/yyyy|MM|dd|hh|mm|ss/g, function(match) { return map[match]; }); } function padZero(num) { return num 10 ? 0 num : num; } // 解析字符串為Date對象 function parseStringToDate(str) { if (!str || typeof str ! string) { return null; } // 嘗試標(biāo)準(zhǔn)解析 var date new Date(str); if (!isNaN(date.getTime())) { return date; } // 嘗試ISO帶T分隔符 var isoMatch str.match(/(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{3}))?(Z|[-]\d{2}:\d{2})?/); if (isoMatch) { var isoStr isoMatch[0]; var isoDate new Date(isoStr); if (!isNaN(isoDate.getTime())) { return isoDate; } } // 手動拆解常見格式 var match str.match(/(\d{4})[-/.](\d{2})[-/.](\d{2})(?:[T\s](\d{2}):(\d{2})(?::(\d{2}))?)?/); if (match) { var year parseInt(match[1], 10); var month parseInt(match[2], 10) - 1; var day parseInt(match[3], 10); var hour match[4] ? parseInt(match[4], 10) : 0; var minute match[5] ? parseInt(match[5], 10) : 0; var second match[6] ? parseInt(match[6], 10) : 0; var result new Date(year, month, day, hour, minute, second); if (!isNaN(result.getTime())) { return result; } } console.warn(parseStringToDate: 無法解析的日期字符串:, str); return null; } // 時間戳轉(zhuǎn)Date自動識別秒級和毫秒級 function timestampToDate(ts) { if (!ts || isNaN(ts)) { return null; } var timestamp Number(ts); if (Math.abs(timestamp) 1e11) { timestamp * 1000; } return new Date(timestamp); } // 字符串直接轉(zhuǎn)毫秒時間戳 function stringToTimestamp(str) { var date parseStringToDate(str); return date ? date.getTime() : 0; } // 獲取當(dāng)前時間的顯示字符串 function now(format) { var defaultFormat format || yyyy-MM-dd hh:mm:ss; return formatDate(new Date(), defaultFormat); }這段代碼里幾個設(shè)計要點.pragma library是QML中定義純JS庫的固定寫法沒有它的話你的JS文件會被當(dāng)作QML對象定義導(dǎo)致導(dǎo)入失敗。這個錯誤信息非常容易讓人誤解如果你在QML中import一個JS文件時遇到奇怪的報錯先檢查第一行是不是寫了這個聲明。4.3 在QML頁面中的實際調(diào)用方式工具庫寫好了接下來看怎么在QML里用import QtQuick 2.15 import DateUtils.js as DateUtils Rectangle { width: 400 height: 200 property string serverTime: 2024-05-20 14:30:00 property int serverTimestamp: 1716190200000 Text { id: displayText anchors.centerIn: parent font.pixelSize: 18 text: displayTime() function displayTime() { // 字符串轉(zhuǎn)時間戳 var ts DateUtils.stringToTimestamp(serverTime); // 時間戳格式化為顯示字符串 var date DateUtils.timestampToDate(ts); return DateUtils.formatDate(date, yyyy年MM月dd日 hh:mm); } } // 注意屬性變化時更新顯示 Connections { target: parent onServerTimeChanged: { displayText.text displayText.displayTime(); } } }這里有一個實際項目中必須注意的地方QML里如果時間字符串是通過外部接口拿到的那么頁面使用日期時通常要放在函數(shù)里而不是屬性綁定里否則容易在初始加載時因為數(shù)據(jù)還沒到達(dá)而顯示空值。屬性綁定的響應(yīng)式更新是QML的優(yōu)勢但對異步數(shù)據(jù)要格外小心判斷空值的場景。4.4 工具庫的擴(kuò)展相對時間與業(yè)務(wù)適配實際業(yè)務(wù)中除了單純的時間戳互轉(zhuǎn)還需要處理很多“包裝”需求。比如列表頁要顯示“3分鐘前”、“昨天”日歷組件要計算某個月有多少天等。// 計算相對時間 function getRelativeTime(date) { if (!(date instanceof Date)) return ; var diff Date.now() - date.getTime(); diff Math.abs(diff); var minute 60 * 1000; var hour 60 * minute; var day 24 * hour; if (diff minute) { return 剛剛; } else if (diff hour) { return Math.floor(diff / minute) 分鐘前; } else if (diff day) { return Math.floor(diff / hour) 小時前; } else if (diff 30 * day) { return Math.floor(diff / day) 天前; } else { return formatDate(date, yyyy-MM-dd); } } // 獲取某月的天數(shù) function getDaysInMonth(year, month) { // month從1開始new Date的月份從0開始 return new Date(year, month, 0).getDate(); }getDaysInMonth這里用了一個JavaScript的經(jīng)典技巧new Date(year, month, 0)中的第0天表示的是上個月的最后一天。比如new Date(2024, 2, 0)就是2024年2月29日閏年它的getDate()就是29于是輕松獲得了2月的天數(shù)。這個技巧比手寫閏年判斷靠譜多了。5. 常見問題與排查技巧實錄5.1 報錯“Invalid Date”時如何恢復(fù)在QML開發(fā)中Invalid Date是最常見的問題。字符串轉(zhuǎn)Date后得到Invalid Date意味著這個日期對象的所有g(shù)et方法都會返回NaN。更麻煩的是你用isNaN(date)判斷不出來的因為date本身不是一個數(shù)字而是一個對象。正確的判斷方式必須用isNaN(date.getTime())。下面這段代碼是我常用的兜底寫法function safeDate(value) { var date new Date(value); if (isNaN(date.getTime())) { // 解析失敗時的降級處理 var match String(value).match(/(\d{4})[-/.](\d{1,2})[-/.](\d{1,2})/); if (match) { return new Date( parseInt(match[1]), parseInt(match[2]) - 1, parseInt(match[3]) ); } // 再不行就返回null讓調(diào)用方?jīng)Q定如何處理 return null; } return date; }這里還有一層經(jīng)驗解析失敗后千萬不要自己去猜用戶意圖給一個null比給一個錯誤日期強得多。錯誤日期會導(dǎo)致后續(xù)所有時間計算都錯位排查起來更痛苦。5.2 “YYYY-MM-dd”被當(dāng)成UTC解析的詭異問題這個坑我必須單獨拿出來講因為太隱蔽了。var date1 new Date(2024-05-20); // 被解析為 UTC 時間 var date2 new Date(2024/05/20); // 被解析為 本地時間 var date3 new Date(2024, 4, 20); // 被解析為 本地時間在東八區(qū)時區(qū)date1.getHours()會返回8而不是0。因為你創(chuàng)建的是一個UTC零點的時間本地顯示就變成了早上8點。date2和date3則沒有這個問題。如果你的業(yè)務(wù)代碼里用new Date(2024-05-20)去格式化日期在東八區(qū)就會得到2024-05-20 08:00再截取年月日可能沒問題但如果后續(xù)要計算時差那就全錯了。解決方案有兩種一是在字符串后面拼上T00:00:00強制按本地時間解析var date new Date(2024-05-20T00:00:00);二是干脆只做日期手動拆解不依賴Date去解析純?nèi)掌谧址?。這也是我上面工具代碼里優(yōu)先采用正則手動解析的原因。5.3 時間戳位數(shù)不對導(dǎo)致日期亂跳時間戳位數(shù)錯誤是接口聯(lián)調(diào)階段最常見的問題之一。秒級時間戳是10位數(shù)字毫秒級是13位數(shù)字差了1000倍。前端展示的數(shù)據(jù)“穿越回1970年”或者“提前3年”基本都是這個原因。這里建議所有QML項目在封裝請求層時就統(tǒng)一做一次時間戳清洗function normalizeTimestamp(ts) { var num Number(ts); if (isNaN(num)) return 0; // 秒級轉(zhuǎn)毫秒級 if (Math.abs(num) 1e11) { return num * 1000; } return num; }另外時間戳為0或者負(fù)數(shù)也是特殊場景。時間戳0代表1970-01-01 00:00:00 UTC有些后端會用0表示“無值”前端要區(qū)分這種情況不要直接顯示1970年。5.4 QML點擊事件報錯后日期控件失效的恢復(fù)有一個熱詞提到了“qml控件點擊事件報錯之后如何恢復(fù)”這個和日期處理確實有關(guān)聯(lián)。我在一個項目里遇到過ListView中有一個時間選擇控件用戶點擊控件時因為日期字符串解析拋出了異常導(dǎo)致控件的onClicked處理函數(shù)中斷結(jié)果整個ListView的點擊事件都變得“沒反應(yīng)”了。這個問題的根源是QML的JavaScript異常處理機制——如果事件處理函數(shù)中拋出了未捕獲的異常QML引擎可能進(jìn)入一個臟狀態(tài)表現(xiàn)為后續(xù)點擊事件全部失效。解決方案是給所有日期解析函數(shù)加上異常保護(hù)和兜底返回function parseStringToDate(str) { // 完全不拋異常永遠(yuǎn)返回null或有效Date try { // 所有解析邏輯 } catch (e) { console.warn(日期解析異常:, e); return null; } }寫日期解析函數(shù)時一個鐵律就是永遠(yuǎn)不要拋異常永遠(yuǎn)返回null或有效日期。讓調(diào)用方去判斷null并做界面降級而不是讓異常一路冒泡到QML引擎最終導(dǎo)致界面交互異常。5.5 日期解析相關(guān)排查速查表癥狀可能原因解決方案顯示“Invalid Date”字符串格式不兼容改用正則手動解析時間差8小時日期部分被解析為UTC拼接T00:00:00或手動拆解時間戳顯示1970年秒級/毫秒級未區(qū)分自動歸一化時間戳單位月份少1個月getMonth()返回值忘了1所有取月份處統(tǒng)一1控件點擊后界面失效事件處理中拋出了異常日期函數(shù)增加異常保護(hù)不拋異常5.6 編譯錯誤與類型問題的關(guān)聯(lián)最后提一個和編譯錯誤相關(guān)的點。QML項目中日期處理導(dǎo)致的編譯錯誤往往不是語法錯誤而是類型推斷錯誤。比如你把一個字符串變量直接傳給一個聲明為date類型的屬性property date targetDate: 2024-05-20 // 這么寫QML會自動轉(zhuǎn)換但格式必須標(biāo)準(zhǔn)如果字符串格式不是QML能自動識別的ISO格式編譯時不會報錯運行時卻會出現(xiàn)字段無效。這類問題在靜態(tài)檢查工具下也不會暴露只能在運行日志里看到一堆警告。建議聲明date類型屬性時一律用new Date()構(gòu)造或者用時間戳賦值不要直接賦裸字符串。經(jīng)驗小結(jié)回到開頭的話題QML里的日期解析難的不是API本身的復(fù)雜度而是它和時區(qū)、格式、類型推斷糾纏在一起時引發(fā)的各種邊界問題。我做這個工具的最終沉淀就是那一個DateUtils.js文件——所有解析走同一套邏輯所有格式化走同一套規(guī)則所有異常統(tǒng)一降級為null。采納這套方案之后我再也沒有因為日期問題加過班。具體到那幾次踩坑最值得反思的還是“YYYY-MM-dd”被當(dāng)作UTC解析的那一次排查過程漫長且沒有規(guī)律如果不是仔細(xì)閱讀了MDN文檔和Qt源碼恐怕很難定位。這種邊界知識基本不會有人手把手教你只能靠實際項目中自己撞出來。如果你最近也在做QML項目建議把文中這個DateUtils工具庫直接拿來用。跑一跑把項目里的日期處理邏輯都走一遍體會一下“統(tǒng)一出口”帶來的維護(hù)便利。等你也踩過幾個時區(qū)的坑你會認(rèn)同我的判斷日期處理不是QML的難點但絕對是最值得提前花心思的地方。