tech-book-labs
ガイド(データユーティリティ) · 2 セクション統合

date-fns v4 日時処理ガイド

date-fns v4 で日時を扱う実装ノート。immutable な関数 API の扱い方(parseISO / format / addDays / differenceInDays)、ロケール / i18n まわりの実装(日本語ロケール + タイムゾーン考慮)までを 1 ページに統合。

著者:TechBook.net編集部 · 最終検証 2026-05-10
セクション · 2026-05-10 · date-fns 4.1.0

date-fns v4 でイミュータブルに日付を扱う

date-fns v4 系の関数型 API(format / parseISO / addDays / differenceInDays / formatDistanceToNow / locale)を最小コードと触れる demo で確認する実装メモ。

検証日: 2026-05-09

使用バージョン: date-fns@4.1.0

対象: ブラウザ / Node で日付を扱う TypeScript プロジェクト、Day.js / Moment からの移行検討中の人

date-fns v4 の イミュータブル関数型 API(format / parseISO / addDays / differenceInDays / formatDistanceToNow)を最小コードで使う記事。動く demo で各関数の挙動が即時確認できます。

触って試す

B − A(日数差)
0
A + 7
2026-05-26 (火曜日)
A の今日比
約9時間前
A は週末?
no

なぜ date-fns(v4)を選ぶか

  • イミュータブル:すべての関数が新しい Date を返す。Moment.js のような chain mutation バグが起きない
  • Tree-shake 可能:必要な関数だけ import すれば bundle が小さい
  • 関数型 API:format(date, fmt) のスタイルで、Date はそのまま使える(独自オブジェクトで包まない)
  • i18n はサブモジュール:date-fns/locale/ja をインポートして渡す(多言語 / 営業日 / 曜日依存ロジックは /articles/date-fns-v4-locale-i18n/ で深掘り)
date-fns の関数型パイプライン — 元の Date は変わらず、各関数が新しい値を返す (クリックで拡大)

Moment.js の moment(d).add(7, 'days') は内部で d を変える ので、共有された moment オブジェクトを後から format するとずれる事故が起きた。date-fns は新しい Date を返すだけなので、そういう副作用バグが起きない。

代替候補と比較:

選択肢特徴
date-fns関数型、tree-shake、Date ベース(現代的標準)
Day.jsAPI は moment 風、軽量。chain 派
LuxonDateTime クラスとタイムゾーン強い
標準 Intl.DateTimeFormatformat だけなら追加 dep 不要
Temporal(stage 3)標準化進行中、polyfill 必要

Temporal が完全 stable になるまでは date-fns が現実的選択。

主な関数

実務で使う関数の組合せ例:parseISO で文字列→Date、format で表示用文字列、addDays / differenceInDays で計算、formatDistanceToNow で相対表現:

import { format, parseISO, addDays, differenceInDays, formatDistanceToNow, isWeekend } from "date-fns";
import { ja } from "date-fns/locale";

const d = parseISO("2026-05-09");          // ISO 文字列 → Date
format(d, "yyyy/MM/dd (EEEE)", { locale: ja });  // "2026/05/09 (土曜日)"
addDays(d, 7);                              // 1 週間後の Date
differenceInDays(d, parseISO("2026-01-01"));  // 128
formatDistanceToNow(d, { addSuffix: true, locale: ja });  // "1 ヶ月後"
isWeekend(d);                               // true(土日判定)

i18n(locale)

date-fns/locale から対象言語の locale を import して、format(date, token, { locale }) の第 3 引数で渡す:

import { format } from "date-fns";
import { ja, enUS } from "date-fns/locale";

format(new Date(), "PPPP", { locale: ja });    // "2026年5月9日土曜日"
format(new Date(), "PPPP", { locale: enUS });  // "Saturday, May 9th, 2026"

PPPP のような長形式は locale token に置き換わる。yyyy-MM-dd のような直接指定はそのまま動く。

つまずいたポイント

  • format の token は Moment と微妙に違う(YYYY ではなく yyyyDD ではなく dd)。古い記事のコードがそのまま動かないことがある
  • タイムゾーン未対応:タイムゾーン横断の操作は date-fns-tz が別途必要
  • new Date(string) の挙動はブラウザ依存:ISO 文字列は parseISO を使うほうが確実
  • format の文字列内で literal を入れる時は '(シングルクォート)で囲むformat(d, "yyyy'年'MM'月'dd'日'") のように

向く / 向かないケース

  • 向く: 表示時の format / 単純な日付計算 / i18n
  • 向かない: タイムゾーン中心の業務(date-fns-tz か Luxon を検討)
  • 向かない: 営業日 / 祝日カレンダー(別ライブラリと組み合わせ)

関連 Topic / 関連書籍

この記事と関係する tech-book.net の Topic と、それぞれの Topic に紐づく書籍:

tech-book.net /books/9784297144944

JavaScriptによるはじめてのアルゴリズム入門

河西 朝雄
詳細を tech-book.net で見る
tech-book.net /books/9784873118086

Python と JavaScriptではじめるデータビジュアライゼーション

Kyran Dale/嶋田 健志/木下 哲也
詳細を tech-book.net で見る
tech-book.net /books/9784839966645

React Native+Expoではじめるスマホアプリ開発 : JavaScriptによるアプリ構築の実際

松澤 太郎 · マイナビ出版 · 2018年

「React Native」は、Facebookが開発しているスマートフォンアプリ向けの開発環境です。ほとんどのコードをJav…

詳細を tech-book.net で見る
tech-book.net /books/9784627857216

はじめてのWebデザイン&プログラミング : HTML、CSS、JavaScript、PHPの基本

村上 祐治
詳細を tech-book.net で見る
tech-book.net /books/9784297138714

フロントエンドの知識地図ーー 一冊でHTML/CSS/JavaScriptの開発技術が学べる本

株式会社ICS 池田 泰延/西原 翼/松本 ゆき
詳細を tech-book.net で見る
セクション · 2026-05-10 · date-fns 4.1.0

date-fns v4 で多言語と曜日 / 営業日を扱う

date-fns v4 の locale サブモジュールを使って format / formatRelative / startOfWeek の挙動を i18n 切替、addBusinessDays / differenceInBusinessDays の営業日計算、format token の locale 依存を触れる demo で確認する実装メモ。

検証日: 2026-05-10

使用バージョン: date-fns@4.1.0

対象: 入門は通っている、多言語サイト / 営業日カレンダー / 曜日依存ロジックを書きたい人

入門記事(format / parseISO / addDays)は別途。本稿は i18n と曜日 / 営業日 の中級パターン。

触って試す

locale:
token説明出力
PPPP完全長(曜日 + 月日)2026年5月10日日曜日
PPP中長(月日 + 年)2026年5月10日
PP短(月日 + 年)2026/05/10
P最短(数値日付)2026/05/10
yyyy-MM-dd EEEEISO 風 + 曜日2026-05-10 日曜日
yyyy 年 M 月 d 日 (EEEE)和文混じり2026 年 5 月 10 日 (日曜日)
今日との相対距離(formatDistanceToNow)
9日前
相対(formatRelative)
2026/05/10
5 営業日後(addBusinessDays)
2026-05-15 金曜日
営業日差(differenceInBusinessDays)
4 営業日
該当週(start–end)
05-1005-16(始週日: locale 依存 ← 今日が週始め)

locale を切り替えると、format token の出力が言語ごとに変わるのが直感的に分かる。

1. locale サブモジュールの import

date-fns/locale から個別の locale(ja / enUS 等)を import し、format 関数の第 3 引数 { locale } で渡す:

import { format, formatDistanceToNow, formatRelative } from "date-fns";
import { ja, enUS, zhCN, ko, fr, de } from "date-fns/locale";

format(new Date(), "PPPP", { locale: ja });    // "2026年5月10日日曜日"
format(new Date(), "PPPP", { locale: enUS });  // "Sunday, May 10th, 2026"
format(new Date(), "PPPP", { locale: zhCN });  // "2026年5月10日 星期日"

ポイント:

  • date-fns/locale から個別 import:import * as locale from "date-fns/locale" は bundle 全体を取り込むので避ける
  • enUS / enGB / enCA を使い分け:アメリカは月日年、イギリスは日月年など
  • { locale } を毎回渡す手間が嫌なら独自 wrapper:fmt(date, "PPPP") のような薄いラッパを作る

2. localized format token(P / PP / PPP / PPPP)

長さで意味が変わる token:

tokenen-USjazh-CN
P05/10/20262026/05/102026/05/10
PPMay 10, 20262026年05月10日2026年5月10日
PPPMay 10th, 20262026年5月10日2026年5月10日
PPPPSunday, May 10th, 20262026年5月10日日曜日2026年5月10日 星期日

yyyy-MM-dd のような直接 token は locale 不依存(数字並びがそのまま)。 P / PP / PPP / PPPPlocale 依存で、一覧やカードのコンパクト表示に推奨。

P/PP/PPP/PPPP token の解決パイプライン — locale ごとの format パターンを引いて、localize で曜日/月名を翻訳 (クリックで拡大)

つまり 同じ token でも出力が locale ごとに大きく変わる のは、format 内部が「pattern 引く → localize で翻訳」の 2 段になっているから。

3. formatRelative / formatDistanceToNow

「いま」を起点とした人間に優しい時間表現:

formatDistanceToNow(date, { addSuffix: true, locale: ja });
// "1分前" / "2日後" / "約1ヶ月前"

formatRelative(date, new Date(), { locale: ja });
// "今日 13:45" / "昨日 09:00" / "先週金曜日 18:30" / "2025/12/01"
  • formatDistanceToNow = 大まかな相対時間(N 分前 / N 日前 / 約 N ヶ月前)
  • formatRelative = 6 日以内は曜日ベース、それ以前は絶対日付

UI のタイムスタンプ表示は formatRelative + tooltip で絶対日時、が王道。

4. 週始まりの locale 依存

startOfWeek / endOfWeek は locale ごとに「週の始まり」が変わる(日本 / 米国 = 日曜、欧州 = 月曜 等):

import { startOfWeek, endOfWeek } from "date-fns";
import { ja, enUS } from "date-fns/locale";

startOfWeek(date, { locale: ja });       // 月曜始まり
startOfWeek(date, { locale: enUS });     // 日曜始まり
startOfWeek(date, { weekStartsOn: 6 });  // 明示的に土曜始まり(Saudi Arabia 等)

ポイント:

  • 明示しないとデフォルト = 日曜始まり(米国ベース)
  • 業務カレンダーが月曜始まりなら locale: ja か weekStartsOn: 1
  • endOfWeek も同じ option を渡す:組で揃える

5. addBusinessDays / differenceInBusinessDays(営業日)

土日を除いた日付計算:

import { addBusinessDays, differenceInBusinessDays } from "date-fns";

addBusinessDays(new Date("2026-05-08"), 5);   // 2026-05-15 (金)
// 5/8(金) → 5/9 5/10 を skip → 5/11 5/12 5/13 5/14 5/15

differenceInBusinessDays(end, start);         // 営業日換算の日数差

簡易な祝日対応ラッパー例:

import HolidayJp from "@holiday-jp/holiday_jp";

function isBusinessDay(d: Date): boolean {
  const day = d.getDay();
  if (day === 0 || day === 6) return false;
  if (HolidayJp.isHoliday(d)) return false;
  return true;
}

function addBusinessDaysJp(date: Date, n: number): Date {
  let cur = date;
  let added = 0;
  while (added < n) {
    cur = addDays(cur, 1);
    if (isBusinessDay(cur)) added++;
  }
  return cur;
}

6. タイムゾーン横断は date-fns-tz

date-fns 本体は タイムゾーン非対応(マシンの local TZ で扱う)。タイムゾーン横断ロジックは date-fns-tz を別途追加:

import { format, toZonedTime, fromZonedTime } from "date-fns-tz";

const utc = new Date("2026-05-10T15:30:00Z");
const tokyo = toZonedTime(utc, "Asia/Tokyo");
format(tokyo, "yyyy-MM-dd HH:mm zzz", { timeZone: "Asia/Tokyo" });
// "2026-05-11 00:30 GMT+9"

UTC で送って 表示時にローカル TZ へ変換 するのが鉄則。new Date(string) の暗黙ローカル化は再現性が壊れやすい。

つまずいたポイント

  • format token の大文字小文字:YYYY ではなく yyyyDD ではなく dd(Moment との違い)
  • literal を含めたい時は '(シングルクォート)で囲む:format(d, "yyyy'年'MM'月'dd'日'")
  • formatRelative の境界:6 日を超えると曜日表示から絶対日付に切り替わる(locale ごとに微妙に違う)
  • { locale: ja } を渡し忘れる:英語表示になっても無音で fallback。表示確認で気付く
  • bundle サイズ:全 locale を取り込むと数百 KB。個別 import + tree-shake が必須
  • タイムゾーン:date-fns 本体は local TZ 固定。混在を避けるなら ISO 8601 (UTC) で persist

関連 Topic / 関連書籍

この記事と関係する tech-book.net の Topic と、それぞれの Topic に紐づく書籍:

tech-book.net /books/9784297144944

JavaScriptによるはじめてのアルゴリズム入門

河西 朝雄
詳細を tech-book.net で見る
tech-book.net /books/9784873118086

Python と JavaScriptではじめるデータビジュアライゼーション

Kyran Dale/嶋田 健志/木下 哲也
詳細を tech-book.net で見る
tech-book.net /books/9784839966645

React Native+Expoではじめるスマホアプリ開発 : JavaScriptによるアプリ構築の実際

松澤 太郎 · マイナビ出版 · 2018年

「React Native」は、Facebookが開発しているスマートフォンアプリ向けの開発環境です。ほとんどのコードをJav…

詳細を tech-book.net で見る
tech-book.net /books/9784627857216

はじめてのWebデザイン&amp;プログラミング : HTML、CSS、JavaScript、PHPの基本

村上 祐治
詳細を tech-book.net で見る
tech-book.net /books/9784297138714

フロントエンドの知識地図ーー 一冊でHTML/CSS/JavaScriptの開発技術が学べる本

株式会社ICS 池田 泰延/西原 翼/松本 ゆき
詳細を tech-book.net で見る

全ガイドは ガイド一覧 から。連載は 連載一覧 へ。