📅
Date や 日時文字列の変換 Intl.DateTimeFormatを使った存在しないフォーマットの作り方
最近は Intl.DateTimeFormat
がとても便利なので 紹介します。
Intl.DateTimeFormat
とは
Intl.DateTimeFormat
は Date
を任意の文字列フォーマットに変換する為のクラスです。
通常は format(date)
で フォーマットします。
ただ、必要なフォーマットが存在しない!今回はそういうときの話です。
formatToParts(date)
の使い方
formatToParts(date)
という 部品単位で どういう部品であるかの情報をつけて出力してくれるものがあります。
つまり、必要な部品を用意してくれるのです。
const from = new Date();
const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
calendar: "iso8601",
fractionalSecondDigits: 3,
timeZoneName: "shortOffset",
};
const format = new Intl.DateTimeFormat("ja-JP", options);
const { year, month, day, hour, minute, second, fractionalSecond, timeZoneName } = ((parts) => {
return Object.fromEntries(parts.filter(({ type }) => type !== "literal").map(({ type, value }) => [type, value])) as {
year: string;
month: string;
day: string;
hour: string;
minute: string;
second: string;
fractionalSecond: string;
timeZoneName: string;
};
})(format.formatToParts(from));
const formatted = `${year}-${month}-${day}T${hour}:${minute}:${second}.${fractionalSecond}`;
console.log(formatted);
// -> "2025-01-19T14:04:22.377
これを使いまわすなら次の様な関数を作るとよいでしょう。
const toLocal = makeToLocal();
{
const date = new Date();
console.log(`${date.toISOString()} -> ${toLocal(date)}`);
// -> "2025-01-19T05:06:41.549Z -> 2025-01-19T14:06:41.549"
}
{
const date = new Date().toISOString();
console.log(`${date} -> ${toLocal(date)}`);
// -> "2025-01-19T05:06:41.551Z -> 2025-01-19T14:06:41.551"
}
/**
* timeZone を local に 変換する
*/
function makeToLocal() {
let toLocalFormat: Intl.DateTimeFormat | undefined;
return toLocal;
/**
* timeZone が local な 日付文字列を返す
*/
function toLocal(from: string): string;
/**
* timeZone が local な Date を返す
*/
function toLocal(from: Date): string;
function toLocal(from: string | Date): string {
const isString = typeof from === "string";
if (isString) {
from = new Date(from as string);
}
if (typeof from === "string") throw new Error();
const { year, month, day, hour, minute, second, fractionalSecond } = ((parts) => {
return Object.fromEntries(parts.filter(({ type }) => type !== "literal").map(({ type, value }) => [type, value])) as {
year: string;
month: string;
day: string;
hour: string;
minute: string;
second: string;
fractionalSecond: string;
timeZoneName: string;
};
})((toLocalFormat ??= initial()).formatToParts(from));
const result = `${year}-${month}-${day}T${hour}:${minute}:${second}.${fractionalSecond}`;
return result;
function initial() {
const options: Intl.DateTimeFormatOptions = {
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
calendar: "iso8601",
fractionalSecondDigits: 3,
timeZoneName: "shortOffset",
};
return new Intl.DateTimeFormat("ja-JP", options);
}
}
}
以上。
Discussion