はじめに
「今日から3営業日後の日付を出したい」「タイムゾーンをまたいだ日時の比較がしたい」——JavaScriptで日付を扱うたびに、こうした地味な計算に手間取った経験はないでしょうか。標準のDateオブジェクトはAPIが古く、月が0始まりだったり、ミュータブルな操作でバグを生みやすかったりと、扱いにくい面が数多くあります。
そんな悩みを解決してくれるのがdate-fnsです。200以上の関数を提供する日付操作ライブラリで、必要な機能だけを取り出して使える軽量さと、純粋関数によるイミュータブルな設計が魅力です。この記事では、date-fnsの特徴から実践的な使い方までを紹介します。
とはいえ、読むより触った方が早いと思います。日付とフォーマット文字列を打ち替えると整形結果がその場で変わるサンプルを置いてあるので、先に挙動を見たい方はこちらからどうぞ。
date-fnsとは
date-fnsは、モダンなJavaScript向けの日付ユーティリティライブラリです。Lodashのように、日付操作に特化した関数を1つずつ独立したモジュールとして提供しており、必要なものだけをインポートして使うことができます。ネイティブのDateオブジェクトをそのまま扱うため、他のライブラリとの相性も良く、学習コストも低いのが特長です。
主な特徴
- 200以上の関数 - フォーマット、比較、加算・減算、パースなど、日付操作に必要な機能を網羅
- Tree-shaking対応 - 使う関数だけをバンドルに含められるため、アプリケーションの容量を抑えられる
- イミュータブル設計 - すべての関数が純粋関数で、常に新しい
Dateインスタンスを返す - TypeScript完全対応 - 100% TypeScriptで書かれており、型定義を別途インストールする必要がない
- 多言語ロケール対応 - 日本語を含む数十言語のロケールが用意されている
- タイムゾーンのファーストクラスサポート - v4.0以降、
@date-fns/tzパッケージのTZDateによってタイムゾーンを扱える
インストール
npm、yarn、pnpmのいずれでもインストールできます。
# npm
npm install date-fns --save
# yarn
yarn add date-fns
# pnpm
pnpm add date-fns
タイムゾーンを扱う場合は、追加で@date-fns/tzもインストールします。
npm install @date-fns/tz --save
date-fnsのサンプルを動かす
書き方の説明に入る前に、まず動かしてみてください。上のカレンダーで日付を選び、下の入力欄にフォーマット文字列を打つと、整形結果が1文字ごとに切り替わります。あわせてformatDistanceToNowによる相対表記と、今日との日数差も表示しています。
フォーマット文字列をPPPPに書き換えると「2026年9月4日金曜日」のような日本語ロケール既定の長い表記に、yyyy/MM/dd HH:mmにすると時刻付きになります。yyyyをYYYYに変えるとエラーが出ますが、これは「YYYYは週基準年なのでyyyyを使ってください」とdate-fns自身が教えてくれているものです。日付を数か月先や数年前に動かせば、相対表記が「約2か月後」「1年前」のように追従するのも確認できます。
このサンプルで使っているdate-fnsのAPIは主に5つです。文字列からDateへの変換にparse、その結果が有効な日付かどうかの判定にisValid、Dateから任意の書式への変換にformatを使い、フォーマット文字列を1文字入力するたびに結果を作り直しています。加えて、現在時刻との相対表記にはformatDistanceToNow、今日との日数差にはdifferenceInCalendarDaysを使っています。骨格だけを抜き出すと、次のようになります。
import { format, parse, isValid, formatDistanceToNow, differenceInCalendarDays } from "date-fns";
import { ja } from "date-fns/locale";
// parseで文字列 → Dateに変換し、isValidで妥当性を確認する
const date = parse("2026-09-04", "yyyy-MM-dd", new Date());
if (isValid(date)) {
// formatはフォーマット文字列を書き換えるだけで表記が変わる
console.log(format(date, "yyyy年MM月dd日(E)", { locale: ja })); // '2026年09月04日(金)'
console.log(format(date, "PPPP", { locale: ja })); // '2026年9月4日金曜日'
// 現在時刻との相対表記・今日との日数差
console.log(formatDistanceToNow(date, { locale: ja, addSuffix: true })); // '約1か月後'
console.log(differenceInCalendarDays(date, new Date())); // 30
}
実際に動かせるものが下です。カレンダーとフォーマット文字列を書き換えると、その場で整形結果・相対表記・日数差が変わります。
ポイントは、出力の形が「フォーマット文字列」というただのテンプレートで決まることです。formatのトークンさえ押さえれば、和暦風の表記も時刻付きも、文字列を書き換えるだけで切り替えられます。さらにparseで文字列からDateへ、formatDistanceToNowでDateから相対表記へと入口と出口の両方が揃っているので、フォームの入力値をそのまま受け取って表示まで持っていけます。ロケールはdate-fns/locale/jaのように必要な言語だけをインポートする形なので、対応言語が多くてもバンドルは膨らみません。
基本的な使い方
もっともよく使う「フォーマット」から見ていきましょう。
import { format } from "date-fns";
const result = format(new Date(2026, 6, 25), "yyyy-MM-dd");
console.log(result); // '2026-07-25'
日付の加算・減算も直感的に書けます。
import { addDays, subMonths } from "date-fns";
const today = new Date(2026, 6, 25);
const nextWeek = addDays(today, 7);
const lastMonth = subMonths(today, 1);
console.log(format(nextWeek, "yyyy-MM-dd")); // '2026-08-01'
console.log(format(lastMonth, "yyyy-MM-dd")); // '2026-06-25'
2つの日付を比較する関数も豊富です。
import { isBefore, differenceInDays } from "date-fns";
const dateA = new Date(2026, 6, 1);
const dateB = new Date(2026, 6, 25);
console.log(isBefore(dateA, dateB)); // true
console.log(differenceInDays(dateB, dateA)); // 24
日本語ロケールを使えば、曜日や月の表記も自然な形で出力できます。
import { format } from "date-fns";
import { ja } from "date-fns/locale";
const result = format(new Date(2026, 6, 25), "yyyy年M月d日(E)", { locale: ja });
console.log(result); // '2026年7月25日(土)'
実践的なユースケース
営業日を考慮した納期計算
業務システムでよくある「土日を除いたN営業日後」の計算です。
import { addDays, isSaturday, isSunday } from "date-fns";
function addBusinessDays(startDate: Date, businessDays: number): Date {
let date = startDate;
let remaining = businessDays;
while (remaining > 0) {
date = addDays(date, 1);
if (!isSaturday(date) && !isSunday(date)) {
remaining -= 1;
}
}
return date;
}
const deadline = addBusinessDays(new Date(2026, 6, 25), 3);
console.log(format(deadline, "yyyy-MM-dd")); // 土日を除いた3営業日後
タイムゾーンをまたいだ日時表示
v4.0で追加されたTZDateを使うと、異なるタイムゾーンでの日時を簡単に扱えます。
import { TZDate } from "@date-fns/tz";
import { format } from "date-fns";
const tokyoTime = new TZDate(2026, 6, 25, 21, 0, 0, "Asia/Tokyo");
const newYorkTime = new TZDate(tokyoTime, "America/New_York");
console.log(format(tokyoTime, "yyyy-MM-dd HH:mm")); // 東京時間
console.log(format(newYorkTime, "yyyy-MM-dd HH:mm")); // ニューヨーク時間に変換
相対的な日時表示
SNSやチャットアプリでよく見る「3日前」「1時間前」のような表示も、1関数で実現できます。
import { formatDistanceToNow } from "date-fns";
import { ja } from "date-fns/locale";
const postedAt = new Date(2026, 6, 22);
console.log(formatDistanceToNow(postedAt, { locale: ja, addSuffix: true }));
// '3日前' のような表示になる
まとめ
date-fnsは、200以上の関数、Tree-shakingによる軽量なバンドルサイズ、イミュータブルな設計、そしてv4.0で加わったタイムゾーンサポートによって、JavaScript/TypeScriptでの日付操作を大きく楽にしてくれるライブラリです。標準のDateオブジェクトの扱いにくさに悩んでいるなら、まずはformatやaddDaysといった基本的な関数から導入してみてはいかがでしょうか。日々の日付処理が驚くほどシンプルになるはずです。