formatISO

2025-05-16

formatISOは、JavaScriptのモダンな日付ユーティリティライブラリであるdate-fnsに含まれる関数の一つです。この関数は、与えられたDateオブジェクトをISO 8601形式の文字列にフォーマットするために使用されます。

ISO 8601とは?

ISO 8601は、日付と時刻の表現に関する国際標準規格です。この規格に従うことで、異なるシステムや地域間で日付と時刻を明確かつ一貫して表現できます。

一般的なISO 8601のフォーマットは以下のようになります。

  • 日付と時刻
    YYYY-MM-DDTHH:mm:ss.sssZ (例: 2024-05-15T10:19:38.000Z)
  • 日付のみ
    YYYY-MM-DD (例: 2024-05-15)

最後のZはUTC(協定世界時)であることを示し、もしタイムゾーンオフセットが含まれる場合は+HH:mm-HH:mmの形式になります。

formatISOの基本的な使い方

formatISOは非常にシンプルで、第一引数にフォーマットしたいDateオブジェクトを渡すだけです。

import { formatISO } from 'date-fns';

const now = new Date(); // 現在の日付と時刻を取得
const isoString = formatISO(now);

console.log(isoString); // 例: "2024-05-15T17:19:38.123Z" (UTCでの出力)

ポイント
formatISOはデフォルトでUTC(協定世界時)の形式で出力します。

オプション引数

formatISOには、出力形式をカスタマイズするためのオプション引数を渡すこともできます。

import { formatISO } from 'date-fns';

const now = new Date();

// 日付のみを出力したい場合 (基本のISO日付形式)
const isoDate = formatISO(now, { format: 'date' });
console.log(isoDate); // 例: "2024-05-15"

// 日付と時刻(秒まで)を出力したい場合
const isoDateTime = formatISO(now, { format: 'extended' });
console.log(isoDateTime); // 例: "2024-05-15T17:19:38Z"

// タイムゾーンオフセットを含めたい場合 (ローカルタイムゾーンで出力)
const isoDateTimeWithOffset = formatISO(now, {
  format: 'extended',
  representation: 'complete', // 秒以下のミリ秒も含む
});
console.log(isoDateTimeWithOffset); // 例: "2024-05-15T10:19:38.123-07:00" (実行環境のタイムゾーン)

主なオプションとその効果は以下の通りです。

  • representation:
    • 'complete' (デフォルト): ミリ秒まで含んだ形式 (YYYY-MM-DDTHH:mm:ss.sssZ)。
    • 'date' (format: 'date'と組み合わせると有効): 日付のみの形式 (YYYY-MM-DD)。
    • 'time' (format: 'extended'と組み合わせると有効): 時間のみの形式 (HH:mm:ss)。
    • 'auto' (デフォルト): 状況に応じて最適な表現を選択。
  • format:
    • 'date' (デフォルト): YYYY-MM-DD形式。
    • 'extended' (デフォルトではありません): YYYY-MM-DDTHH:mm:ss形式。

formatISOを使うメリット

  • 堅牢性
    date-fnsは日付操作において信頼性が高く、エッジケースも適切に処理します。
  • シンプルさ
    複雑なフォーマット文字列を覚える必要がなく、簡単にISO形式の文字列を取得できます。
  • 一貫性
    常に予測可能な形式で日付文字列を生成できます。
  • 国際標準への準拠
    日付と時刻のフォーマットがISO 8601に準拠するため、異なるシステム間でのデータ交換が容易になります。


formatISOは比較的シンプルで使いやすい関数ですが、それでもいくつか共通のエラーや疑問点が発生することがあります。

入力値がDateオブジェクトではない

エラーの症状
formatISODateオブジェクトではない値を渡すと、予期しない結果になったり、エラーが発生したりします。例えば、nullundefined、日付文字列を直接渡した場合などです。

import { formatISO } from 'date-fns';

console.log(formatISO(null));       // Invalid Date となるか、エラーになる
console.log(formatISO(undefined));  // Invalid Date となるか、エラーになる
console.log(formatISO('2024-05-15')); // "Invalid Date" のような文字列が出力される

原因
formatISOは第一引数に有効なJavaScriptのDateオブジェクトを期待しています。日付文字列はそのままではDateオブジェクトとして認識されません。

トラブルシューティング
formatISOに渡す前に、入力値が有効なDateオブジェクトであることを確認してください。文字列からDateオブジェクトを生成する場合は、new Date()を使うか、date-fnsparseISOparse関数を使用します。

import { formatISO, parseISO } from 'date-fns';

// 1. new Date() で変換
const dateString = '2024-05-15T10:30:00Z';
const dateObj = new Date(dateString);
console.log(formatISO(dateObj)); // "2024-05-15T10:30:00.000Z"

// 2. parseISO を使用 (ISO 8601形式の文字列の場合)
const parsedDate = parseISO(dateString);
console.log(formatISO(parsedDate)); // "2024-05-15T10:30:00.000Z"

// 3. 入力値の検証
function safelyFormatISO(dateInput) {
  if (dateInput instanceof Date && !isNaN(dateInput.getTime())) {
    return formatISO(dateInput);
  } else {
    console.warn("Invalid date input provided to formatISO:", dateInput);
    return null; // または適切なエラー処理
  }
}
console.log(safelyFormatISO(new Date()));
console.log(safelyFormatISO('not a date'));

タイムゾーンのずれ(UTC vs. ローカルタイム)

エラーの症状
formatISOで出力される時刻が、自分が期待するタイムゾーン(例えばローカルタイム)と異なる(通常はUTCになる)と感じることがあります。

import { formatISO } from 'date-fns';

const now = new Date(); // 日本で実行した場合、JST(UTC+9)の現在時刻
console.log(now.toString());     // 例: "Wed May 15 2024 19:30:00 GMT+0900 (日本標準時)"
console.log(formatISO(now));     // 例: "2024-05-15T10:30:00.000Z" (UTC時刻)

原因
formatISOは、デフォルトで**UTC(協定世界時)**に基づいたISO 8601形式で出力します。これはISO 8601の標準的な動作であり、異なるタイムゾーン間での日付時刻のやり取りにおいて混乱を避けるためのものです。ZはUTCであることを示します。

トラブルシューティング

  • ローカルタイムゾーンで出力したい場合
    formatISO自体はタイムゾーン変換の機能を持っていません。ローカルタイムゾーンのオフセットを含んだISO形式の文字列が欲しい場合は、representation: 'complete'オプションを使用します。
  • formatISOのデフォルト動作を理解する
    formatISOがUTCで出力することは正しい動作です。APIとの連携やデータベースへの保存など、多くの場合はUTC形式が望ましいです。

<!-- end list -->

import { formatISO } from 'date-fns';

const now = new Date(); // ローカルタイムゾーンの現在時刻

// ローカルタイムゾーンのオフセットを含んだISO形式
// 例えば、JST (UTC+9) の場合: "2024-05-15T19:30:00.000+09:00"
console.log(formatISO(now, { representation: 'complete' }));

// タイムゾーン変換を明示的に行いたい場合
// date-fnsにはタイムゾーン処理のための date-fns-tz ライブラリが推奨されます。
// import { formatInTimeZone } from 'date-fns-tz';
// const zonedDate = formatInTimeZone(now, 'Asia/Tokyo', 'yyyy-MM-dd HH:mm:ssXXX');
// console.log(zonedDate); // 例: "2024-05-15 19:30:00+09:00"

注意
formatISO(date, { representation: 'complete' })は、実行環境のローカルタイムゾーンオフセットを付加しますが、特定のタイムゾーンを指定して変換したい場合はdate-fns-tzの使用を検討してください。

必要な形式と異なる出力(秒、ミリ秒の有無、日付のみなど)

エラーの症状
formatISOの出力が、期待する厳密なISO 8601形式(例えば、秒以下は不要、日付のみ欲しいなど)と異なる。

import { formatISO } from 'date-fns';

const now = new Date();
console.log(formatISO(now)); // "2024-05-15T10:30:00.123Z" (ミリ秒まで出力される)
// 欲しいのは "2024-05-15T10:30:00Z" の場合

原因
formatISOにはデフォルトのフォーマットと、それを変更するためのオプションがあります。オプションを適切に指定しないと、デフォルトの出力形式になります。

トラブルシューティング
formatISOのオプション引数を使用して、出力形式をカスタマイズします。

  • より複雑なカスタムフォーマットが必要な場合
    formatISOではなく、より汎用的なformat関数を使用します。format関数は、指定されたトークンに基づいて日付をフォーマットします。

    import { format } from 'date-fns';
    
    const now = new Date();
    
    // 例: YYYY-MM-DDTHH:mm:ss (タイムゾーン情報なし)
    console.log(format(now, "yyyy-MM-dd'T'HH:mm:ss")); // 例: "2024-05-15T19:30:00" (ローカルタイム)
    
    // 例: YYYY-MM-DDTHH:mm:ss (UTCで出力)
    // UTCでのフォーマットは少し複雑になりますが、date-fns-tz を使うのが最も簡単です。
    // import { utcToZonedTime, format } from 'date-fns-tz';
    // const utcDate = utcToZonedTime(now, 'UTC');
    // console.log(format(utcDate, "yyyy-MM-dd'T'HH:mm:ss'Z'"));
    
  • 日付のみが必要な場合
    formatオプションを'date'に設定します。

    import { formatISO } from 'date-fns';
    const now = new Date();
    // YYYY-MM-DD 形式
    console.log(formatISO(now, { format: 'date' })); // 例: "2024-05-15"
    
  • 秒以下(ミリ秒)を省きたい場合
    formatオプションを'extended'に設定します。

    import { formatISO } from 'date-fns';
    const now = new Date();
    // YYYY-MM-DDTHH:mm:ssZ 形式 (ミリ秒なし)
    console.log(formatISO(now, { format: 'extended' })); // 例: "2024-05-15T10:30:00Z"
    

date-fnsのバージョンによる違い

エラーの症状
以前のプロジェクトでは動いたコードが、新しいプロジェクトでは動かない、または異なる結果になる。

原因
date-fnsは定期的にアップデートされ、マイナーな変更やAPIの修正が含まれることがあります。特にメジャーバージョンアップ(例: v1からv2、v2からv3)では破壊的変更が含まれる可能性があります。

トラブルシューティング

  • 依存関係の固定
    package.jsondate-fnsのバージョンを固定し(例: "date-fns": "2.x.x"ではなく"date-fns": "^2.30.0"のように)、予期せぬバージョンアップを防ぎます。
  • 変更履歴(Changelog)の確認
    GitHubのリポジトリやnpmのパッケージページで変更履歴を確認し、関連する変更がないか調べます。


formatISOは、JavaScriptのDateオブジェクトをISO 8601形式の文字列に変換する際に非常に便利です。ここでは、いくつかの一般的な使用例と、そのコードを示します。

まず、例を実行するためにdate-fnsをインストールする必要があります。

npm install date-fns
# または
yarn add date-fns

基本的な使用法:現在の日時をISO 8601形式で出力

最も基本的な使い方は、DateオブジェクトをformatISOに渡すだけです。デフォルトでは、ミリ秒まで含んだUTC(協定世界時)形式の文字列が生成されます。

import { formatISO } from 'date-fns';

// 1. 現在の日時を取得
const now = new Date();
console.log('現在のDateオブジェクト:', now.toString());
// 例: "Thu May 15 2025 10:22:11 GMT-0700 (Pacific Daylight Time)" (実行環境のタイムゾーン)

// 2. formatISOでISO 8601形式に変換
const isoStringDefault = formatISO(now);
console.log('デフォルトのISO 8601形式:', isoStringDefault);
// 例: "2025-05-15T17:22:11.123Z" (UTCでの出力、ZはUTCを示す)

解説
formatISOは、渡されたDateオブジェクトの時刻をUTCに変換し、Z(Zulu time、UTCの別名)を付加した形式で出力します。ミリ秒も含まれるのがデフォルトの動作です。

日付のみをISO 8601形式で出力

時刻情報が必要なく、日付だけをYYYY-MM-DD形式で出力したい場合は、オプション{ format: 'date' }を使用します。

import { formatISO } from 'date-fns';

const today = new Date(); // 今日の日付
const isoDateOnly = formatISO(today, { format: 'date' });
console.log('日付のみのISO 8601形式:', isoDateOnly);
// 例: "2025-05-15"

解説
このオプションを指定すると、時刻情報は完全に無視され、日付部分のみがISO 8601の標準形式で出力されます。

秒まで含んだISO 8601形式で出力(ミリ秒なし)

ミリ秒は不要で、秒まで含んだYYYY-MM-DDTHH:mm:ssZ形式で出力したい場合は、オプション{ format: 'extended' }を使用します。

import { formatISO } from 'date-fns';

const specificTime = new Date(2025, 4, 15, 10, 30, 45, 999); // 2025年5月15日 10:30:45.999 (ローカルタイム)
console.log('元のDateオブジェクト:', specificTime.toString());

const isoStringSeconds = formatISO(specificTime, { format: 'extended' });
console.log('秒まで含んだISO 8601形式:', isoStringSeconds);
// 例: "2025-05-15T17:30:45Z" (UTCに変換された結果)

解説
'extended'オプションは、YYYY-MM-DDTHH:mm:ssの形式で出力します。デフォルトと同様にUTCに変換されます。

ローカルタイムゾーンのオフセットを含んだISO 8601形式で出力

formatISOのデフォルトはUTCですが、実行環境のローカルタイムゾーンのオフセット(例: +09:00-07:00)を含んだISO 8601形式で出力したい場合は、{ representation: 'complete' }オプションを使用します。これは、YYYY-MM-DDTHH:mm:ss.sss±HH:mmの形式になります。

import { formatISO } from 'date-fns';

const nowLocal = new Date(); // 現在のローカル日時
console.log('現在のDateオブジェクト (ローカル):', nowLocal.toString());
// 例: "Thu May 15 2025 10:22:11 GMT-0700 (Pacific Daylight Time)"

const isoStringWithOffset = formatISO(nowLocal, { representation: 'complete' });
console.log('ローカルタイムゾーンオフセットを含むISO 8601形式:', isoStringWithOffset);
// 例: "2025-05-15T10:22:11.123-07:00" (実行環境のタイムゾーンオフセット)

解説
representation: 'complete'は、日付、時刻、ミリ秒、そして実行環境のタイムゾーンオフセットをすべて含んだ形式で出力します。これは、特定のタイムゾーンを明示したい場合に便利ですが、特定のタイムゾーン(例: 東京時間、ニューヨーク時間)を指定して変換するわけではないことに注意してください。特定のタイムゾーンへの変換には、のような拡張ライブラリを使用する必要があります](https://www.google.com/search?q=https://github.com/marnusw/date-fns-tz)%E3%81%AE%E3%82%88%E3%81%86%E3%81%AA%E6%8B%A1%E5%BC%B5%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AA%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99)。

文字列からDateオブジェクトに変換してformatISOを使用する

APIから受け取った日付文字列など、すでに文字列形式の日付がある場合、それをDateオブジェクトに変換してからformatISOを使用するのが一般的です。date-fnsparseISO関数が便利です。

import { formatISO, parseISO } from 'date-fns';

const apiDateString = '2023-11-20T14:00:00.000Z'; // ISO 8601形式のAPIからの文字列

// 1. 文字列をDateオブジェクトにパース
const parsedDate = parseISO(apiDateString);
console.log('パース後のDateオブジェクト:', parsedDate.toString());
// 例: "Mon Nov 20 2023 06:00:00 GMT-0800 (Pacific Standard Time)" (元のUTCがローカルに変換されて表示)

// 2. パースしたDateオブジェクトを再度ISO 8601形式にフォーマット
const reFormattedIso = formatISO(parsedDate);
console.log('再フォーマットされたISO 8601形式:', reFormattedIso);
// 例: "2023-11-20T14:00:00.000Z" (元のUTC形式に戻る)

// parseISOがISO 8601以外の形式の文字列を扱う場合
const customDateString = '2022/10/25 15:30';
// formatISO(customDateString) は 'Invalid Date' になるので、
// new Date() または parse 関数を使う
const dateFromCustomString = new Date(customDateString); // または parse(customDateString, 'yyyy/MM/dd HH:mm', new Date())
console.log('カスタム文字列から変換:', formatISO(dateFromCustomString));
// 例: "2022-10-25T22:30:00.000Z" (実行環境のタイムゾーンに基づいてUTCに変換)

解説
parseISOはISO 8601形式の文字列を安全にDateオブジェクトに変換します。その後、formatISOを使って再度ISO 8601形式の文字列として整形できます。これにより、日付のパースとフォーマットの一貫性を保つことができます。



JavaScriptの組み込みDate.prototype.toISOString()

これは最も直接的で、外部ライブラリを必要としない方法です。JavaScriptのDateオブジェクトに元々備わっているメソッドです。

特徴

  • ブラウザ/Node.jsサポート
    広くサポートされています。
  • カスタマイズ不可
    formatISOのように日付のみ、秒まで、タイムゾーンオフセットを含むなど、出力形式をカスタマイズするオプションはありません。
  • 出力形式
    常にYYYY-MM-DDTHH:mm:ss.sssZの形式で出力されます。これはUTC(協定世界時)を表し、ミリ秒まで含みます。
  • シンプルさ
    外部ライブラリのインポートが不要。

コード例

const now = new Date();
console.log('Dateオブジェクト:', now.toString());
// 例: "Thu May 15 2025 10:23:28 GMT-0700 (Pacific Daylight Time)"

const isoStringNative = now.toISOString();
console.log('toISOString()での出力:', isoStringNative);
// 例: "2025-05-15T17:23:28.123Z" (UTCでの出力)

いつ使うべきか

  • 特定のカスタマイズが不要な場合。
  • 外部ライブラリの依存関係を増やしたくない場合。
  • 最も標準的なISO 8601形式(UTC、ミリ秒付き)が欲しい場合。

date-fnsのformat関数

date-fnsformat関数は、日付を任意の文字列形式にフォーマットするための非常に強力で柔軟なツールです。ISO 8601形式に限らず、どのような日付文字列でも生成できます。

特徴

  • タイムゾーン対応
    date-fns-tzライブラリと組み合わせることで、特定のタイムゾーンでの出力が可能です。
  • 国際化対応
    ロケール(言語)を指定することで、日付の曜日や月の名称などをその言語で出力できます(formatISOは国際化に影響されません)。
  • 高い柔軟性
    フォーマット文字列(例: 'yyyy-MM-dd', 'HH:mm:ss', 'yyyy-MM-dd\'T\'HH:mm:ssXXX')を自由に指定することで、厳密なISO 8601形式だけでなく、あらゆるカスタム形式を生成できます。

コード例(ISO 8601の代替として)

import { format } from 'date-fns';
import { utcToZonedTime } from 'date-fns-tz'; // タイムゾーン対応が必要な場合

const now = new Date();

// ISO 8601日付のみ (YYYY-MM-DD)
const isoDateOnly = format(now, 'yyyy-MM-dd');
console.log('formatで日付のみ:', isoDateOnly);
// 例: "2025-05-15" (ローカルタイム)

// ISO 8601拡張形式(秒まで、UTC)
// 'X' は ISO 8601 のタイムゾーンオフセットを表すトークン
// 'Z' は UTC を表すリテラル(UTCであるという明示的な指定)
const isoSecondsUTC = format(utcToZonedTime(now, 'UTC'), "yyyy-MM-dd'T'HH:mm:ss'Z'");
console.log('formatで秒まで(UTC):', isoSecondsUTC);
// 例: "2025-05-15T17:23:28Z"

// ローカルタイムゾーンオフセットを含む形式
// 'XXX' はローカルのタイムゾーンオフセット(例: -07:00)
const isoWithOffset = format(now, "yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
console.log('formatでローカルオフセット:', isoWithOffset);
// 例: "2025-05-15T10:23:28.123-07:00"

いつ使うべきか

  • ローカルタイムゾーンで厳密にフォーマットしたい場合(date-fns-tzと併用)。
  • ISO 8601以外のカスタム日付フォーマットも生成する必要がある場合。
  • formatISOでは実現できない、より細かい形式の制御が必要な場合。

かつては広く使われていた強力な日付ライブラリですが、現在は開発が停止しており、新規プロジェクトでの使用は推奨されていません。しかし、既存のプロジェクトではまだ見かけることがあります。

特徴

  • 非推奨
    今後、セキュリティパッチや新機能の追加がないため、date-fnsluxonなどのモダンなライブラリへの移行が推奨されています。
  • フォーマット機能
    format()メソッドでカスタムフォーマットが可能です。
  • 直感的
    非常に使いやすいAPIを提供していました。

コード例

// Moment.jsはインストールが必要です: npm install moment
// import moment from 'moment'; // Moment.jsは通常、グローバルに公開されるか、直接インポート

// const now = moment();
// const isoStringMoment = now.toISOString(); // toISOString() は Moment オブジェクトにもあります
// console.log('Moment.js toISOString():', isoStringMoment);

// const customIsoFormat = now.format('YYYY-MM-DDTHH:mm:ssZ');
// console.log('Moment.js custom ISO format:', customIsoFormat);

いつ使うべきか

  • 既存のMoment.jsベースのプロジェクトで、一時的に日付フォーマットを行う場合。
  • 新規プロジェクトでは使わないでください。

Luxon

Moment.jsの代替として登場したモダンな日付ライブラリで、イミュータブルなオブジェクトと堅牢なタイムゾーンサポートが特徴です。

特徴

  • 明確なAPI
    Moment.jsと同様に直感的でありながら、よりモダンな設計です。
  • 堅牢なタイムゾーン
    国際的なタイムゾーン処理に優れています。
  • イミュータブル
    日付操作が元のオブジェクトを変更せず、新しいオブジェクトを返します。

コード例

import { DateTime } from 'luxon';

const nowLuxon = DateTime.local(); // ローカルタイムゾーンの現在日時
console.log('Luxon DateTimeオブジェクト:', nowLuxon.toString());
// 例: "2025-05-15T10:23:28.123-07:00"

const isoLuxonDefault = nowLuxon.toISO();
console.log('Luxon toISO() (デフォルト):', isoLuxonDefault);
// 例: "2025-05-15T10:23:28.123-07:00" (ローカルタイムゾーンオフセットを含む)

const isoLuxonUTC = nowLuxon.toUTC().toISO();
console.log('Luxon toISO() (UTC):', isoLuxonUTC);
// 例: "2025-05-15T17:23:28.123Z"

const isoLuxonDateOnly = nowLuxon.toISODate();
console.log('Luxon toISODate():', isoLuxonDateOnly);
// 例: "2025-05-15"

const isoLuxonTimeOnly = nowLuxon.toISOTime();
console.log('Luxon toISOTime():', isoLuxonTimeOnly);
// 例: "10:23:28.123-07:00"
  • date-fnsとは異なるアプローチ(オブジェクト指向的)を好む場合。
  • プロジェクト全体で強力なタイムゾーン処理とイミュータブルな日付オブジェクトが必要な場合。
方法特徴デフォルト出力例カスタマイズ性
Date.prototype.toISOString()組み込み、外部ライブラリ不要、UTC固定、ミリ秒含む2025-05-15T17:23:28.123Z
date-fns format高い柔軟性、任意のフォーマット文字列、国際化、date-fns-tzと併用でタイムゾーン対応yyyy-MM-ddなどトークンによる
Luxon toISO()イミュータブル、堅牢なタイムゾーン処理、明確なAPI2025-05-15T10:23:28.123-07:00など中〜高