JSON UTC 時間轉 yyyy-MM-mm HH:mm:ss 格式本地時間之香草 JavaScript 極簡解法
4 | 9,701 |
生活與工作上遇過多次,從後端接到 2023-07-25T23:30:00Z JSON 格式的 UTC 時間字串,new Date('2023-07-25T23:30:00Z') 轉成 Date 物件後,不想為此引用程式庫,如何用原生 API 再轉成本地時間的 yyyy-MM-mm HH:mm:ss 格式 2023-07-26 07:30:00
?
.toISOString() 可得到格式很接近的答案,但它一律使用 UTC 時區沒得修改,必須自己換算再去掉 T 及結尾的 Z;另一個是問 ChatGPT 常會得到的答案,乖乖用 getFullYear()、.getMonth()(記得要加 1)... 取值再前方補零至兩位,直覺好懂,但太囉嗦了,不合我的胃口。
var d = new Date('2023-07-25T23:30:00Z');
console.log(d.toString());
console.log(d.toISOString());
// 方法一 由 ChatGPT
function f1(d) {
let year = d.getFullYear();
let month = ("0" + (d.getMonth() + 1)).slice(-2); // Month is zero-based
let day = ("0" + d.getDate()).slice(-2);
let hour = ("0" + d.getHours()).slice(-2);
let minute = ("0" + d.getMinutes()).slice(-2);
let second = ("0" + d.getSeconds()).slice(-2);
return year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second;
}
// 方法一 換算時區後 toISOString() 再去掉 T 及結尾 Z
function f2(d) {
d = new Date(d.getTime() - d.getTimezoneOffset()*60*1000);
return d.toISOString().replace('T',' ').substr(0, 19);
}
console.log(f1(d));
console.log(f2(d));
今天意外找到一個超精簡的巧妙解法,toLocaleString('sv'),這樣就好了!
var d = new Date('2023-07-25T23:30:00Z');
console.log(d.toLocaleString('sv'));
.toLocaleString() API支援 地區設定參數(Locale,如台灣是 zh-TW、美國是 en-US),而 sv 是瑞典(Swedish)的地區代碼,巧的是瑞典慣用的日期格式是 yyyy-MM-dd,時間格式是 HH:mm:ss (24 小時制),就醬,不費吹灰之力就得到我們要的 yyyy-MM-dd HH:mm:ss。
好奇還有哪些國家地區也是用 yyyy-MM-dd HH:mm:ss?我在 Github 找到一份完整地區名稱清單,但不是所有 Locale JavaScript 都支援,要先用 Intl.DateTimeFormat.supportedLocalesOf() 篩選,我寫了一小段程式,掃過一輪,找到共有 11 個地區是用 yyyy-MM-dd HH:mm:ss:
<!DOCTYPE html>
<html>
<head>
<title>demo</title>
<meta charset="utf-8">
</head>
<body>
<!-- data source: https://github.com/umpirsky/locale-list/blob/master/data/en/locales.json -->
<script src="locales.js"></script>
<script>
//replace _ to - for locale name
const data = {};
Object.keys(localeData).forEach(l =>
data[l.replace(/_/g, '-')] = localeData[l]
);
const date = new Date('2023-08-08T10:00:00Z');
const noSupportList = [];
const locales =
Object.keys(data)
.filter(l => {
let valid = Intl.DateTimeFormat.supportedLocalesOf(l).length > 0;
if (!valid) noSupportList.push(l);
return valid;
});
locales.sort();
locales.forEach(function (locale) {
locale = locale.replace('_', '-');
const str = date.toLocaleString(locale);
if (str == '2023-08-08 18:00:00') {
console.log(`${str} ${locale}, ${data[locale]}`);
}
});
console.log('unsupported locales: ' + noSupportList.join(', '));
</script>
</body>
</html>
若求簡短,除了 sv (瑞典),af (阿富汗)、ky (吉爾吉斯)、lt (立陶宛) 也是好選擇。
同場加映,如果是 yyyy/MM/dd HH:mm:ss 呢?答案是沒有現成地區符合,需要加點工,toLocaleString() 時指定年月日時分秒補零到兩位,hour12 = false 切 24 小時制,如此有 9 個地區代碼吻合,求簡短可以用 jp、zh,或是直接用 zh-TW 最好記:
locales.forEach(function (locale) {
locale = locale.replace('_', '-');
const str = date.toLocaleString(locale, {
year: 'numeric',
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit',
second: '2-digit',
hour12: false
});
if (str == '2023/08/08 18:00:00') {
console.log(`${str} ${locale}, ${data[locale]}`);
}
});
Tips of using toLocaleString('sv') to get local time string in yyyy-MM-dd HH:mm:ss format.
Comments
# by Anonymous
好文! yyyy/MM/dd HH:mm:ss 懶得記 用 (new Date()).toLocaleString('af').replaceAll('-', '/') 好了
# by ByTim
若是後臺傳的DateTime XXX,可能要先判斷instanceof Date,如以下程式碼。 if(XXX instanceof Date){var yyyy = XXX.getFullYear(); ... }else{XXX = XXX.replace("T00:00:00", ""); ... }
# by MollyLin
如果不考慮舊 IE 的話,還有更簡單的寫法哦~ const date = new Date("2022-10-27T16:00:30.676Z"); let options = { timeZone: "UTC", dateStyle: "short", timeStyle: "medium", }; console.log(new Intl.DateTimeFormat("sv", options).format(date)); // 2022-10-27 16:00:30
# by Molly Lin
直接取上方的 options,不介意中文字的上下午的話,使用本地化 "zh-TW" 可輸出為: console.log(new Intl.DateTimeFormat("zh-TW", options).format(date)); // 2022/10/27 下午4:00:30