11

JSON UTC 時間轉 yyyy-MM-mm HH:mm:ss 格式本地時間之香草 JavaScript 極簡解法

 1 year ago
source link: https://blog.darkthread.net/blog/js-date-yyyymmdd-hhmmss/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

JSON UTC 時間轉 yyyy-MM-mm HH:mm:ss 格式本地時間之香草 JavaScript 極簡解法-黑暗執行緒

生活與工作上遇過多次,從後端接到 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'));

Fig1_638259786484769987.png

.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 (立陶宛) 也是好選擇。

Fig2_638259786488415728.png

同場加映,如果是 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]}`);
    }
});

Fig3_638259786490267853.png

and has 1 comment

Comments

Post a comment

Comment
Name Captcha 17 + 10 =

Recommend

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK