Claude Codeで日付・時間の扱いを正しく実装する
Claude Codeを使って、タイムゾーン対応・日付フォーマット・相対時間表示などの日付・時間処理を正しく実装する方法を解説します。
日付・時間処理をClaude Codeで正しく実装する
日付と時間の処理は、タイムゾーン、フォーマット、ロケール対応など思わぬ落とし穴が多い領域です。Claude Codeを使えば、ベストプラクティスに沿った堅牢な日付処理を効率的に実装できます。
ライブラリの選択
> 日付・時間の処理ユーティリティを作って。
> day.jsを使って、タイムゾーン変換、相対時間表示、
> 日本語フォーマット、営業日計算を実装して。
- day.js: 軽量(2KB)で Moment.js 互換のAPI
- date-fns: 関数ベース、Tree-shakingに最適
- Temporal API: 将来の標準API(まだ提案段階)
日付ユーティリティの実装
// src/lib/date-utils.ts
import dayjs from 'dayjs';
import utc from 'dayjs/plugin/utc';
import timezone from 'dayjs/plugin/timezone';
import relativeTime from 'dayjs/plugin/relativeTime';
import 'dayjs/locale/ja';
dayjs.extend(utc);
dayjs.extend(timezone);
dayjs.extend(relativeTime);
dayjs.locale('ja');
// デフォルトタイムゾーン
const DEFAULT_TZ = 'Asia/Tokyo';
// フォーマットのプリセット
export const DATE_FORMATS = {
full: 'YYYY年M月D日(ddd) HH:mm',
date: 'YYYY年M月D日',
dateShort: 'M/D',
time: 'HH:mm',
iso: 'YYYY-MM-DDTHH:mm:ssZ',
api: 'YYYY-MM-DD',
} as const;
/**
* UTCの日付文字列をJSTでフォーマット
*/
export function formatDate(
date: string | Date,
format: keyof typeof DATE_FORMATS = 'date'
): string {
return dayjs(date).tz(DEFAULT_TZ).format(DATE_FORMATS[format]);
}
/**
* 相対時間を返す(「3分前」「2時間前」「昨日」など)
*/
export function timeAgo(date: string | Date): string {
const d = dayjs(date);
const now = dayjs();
const diffHours = now.diff(d, 'hour');
if (diffHours < 1) {
const diffMinutes = now.diff(d, 'minute');
if (diffMinutes < 1) return 'たった今';
return `${diffMinutes}分前`;
}
if (diffHours < 24) return `${diffHours}時間前`;
if (diffHours < 48) return '昨日';
if (diffHours < 168) return `${Math.floor(diffHours / 24)}日前`;
return formatDate(date, 'date');
}
/**
* タイムゾーン変換
*/
export function convertTimezone(
date: string | Date,
fromTz: string,
toTz: string
): dayjs.Dayjs {
return dayjs.tz(date, fromTz).tz(toTz);
}
/**
* 営業日かどうかを判定
*/
export function isBusinessDay(date: string | Date): boolean {
const d = dayjs(date);
const dayOfWeek = d.day();
return dayOfWeek !== 0 && dayOfWeek !== 6; // 日曜=0, 土曜=6
}
/**
* N営業日後の日付を取得
*/
export function addBusinessDays(date: string | Date, days: number): dayjs.Dayjs {
let current = dayjs(date);
let remaining = days;
while (remaining > 0) {
current = current.add(1, 'day');
if (isBusinessDay(current.toDate())) {
remaining--;
}
}
return current;
}
Intl APIによるネイティブフォーマット
ライブラリなしでも、ブラウザのIntlAPIで多くのフォーマットが可能です。
// src/lib/intl-date.ts
/**
* Intl.DateTimeFormatを使った日付フォーマット
*/
export function formatDateIntl(date: Date, style: 'long' | 'short' = 'long'): string {
return new Intl.DateTimeFormat('ja-JP', {
year: 'numeric',
month: style === 'long' ? 'long' : 'numeric',
day: 'numeric',
weekday: style === 'long' ? 'short' : undefined,
}).format(date);
}
/**
* 2つの日付の差を人間が読める形式で表示
*/
export function formatDateRange(start: Date, end: Date): string {
return new Intl.DateTimeFormat('ja-JP', {
year: 'numeric',
month: 'short',
day: 'numeric',
}).formatRange(start, end);
}
/**
* 相対時間のフォーマット
*/
export function formatRelative(date: Date): string {
const rtf = new Intl.RelativeTimeFormat('ja', { numeric: 'auto' });
const now = new Date();
const diffMs = date.getTime() - now.getTime();
const diffSec = Math.round(diffMs / 1000);
const diffMin = Math.round(diffSec / 60);
const diffHour = Math.round(diffMin / 60);
const diffDay = Math.round(diffHour / 24);
if (Math.abs(diffSec) < 60) return rtf.format(diffSec, 'second');
if (Math.abs(diffMin) < 60) return rtf.format(diffMin, 'minute');
if (Math.abs(diffHour) < 24) return rtf.format(diffHour, 'hour');
return rtf.format(diffDay, 'day');
}
Reactコンポーネントでの利用
// src/components/TimeDisplay.tsx
'use client';
import { useState, useEffect } from 'react';
import { timeAgo } from '@/lib/date-utils';
export function TimeDisplay({ date }: { date: string }) {
const [display, setDisplay] = useState(timeAgo(date));
useEffect(() => {
const interval = setInterval(() => {
setDisplay(timeAgo(date));
}, 60000); // 1分ごとに更新
return () => clearInterval(interval);
}, [date]);
return (
<time dateTime={date} title={new Date(date).toLocaleString('ja-JP')}>
{display}
</time>
);
}
よくある落とし穴
- タイムゾーン未考慮: サーバーとクライアントでタイムゾーンが異なる場合、常にUTCで保存しクライアントで変換する
- 夏時間: 日本にはないが、海外ユーザー対応時は要注意
- Date.parse()の挙動: ブラウザ間で差異があるため、dayjs等でパースする
関連記事
国際化対応全般はi18n実装ガイド、通貨のフォーマットは通貨フォーマットの実装を参考にしてください。
day.jsの公式ドキュメント(day.js.org)でプラグイン一覧を確認できます。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
現役DX室長|Claude Code でゼロから多言語AI技術メディア運営中。実務直結の自動化、AI開発相談・研修受付中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Codeで多言語記事を毎日公開するための7つのデプロイ前チェック
日本語だけ公開して終わらせないために、Claude Codeで多言語記事を毎日出す前に確認したい7つのチェックを実例つきで整理しました。
Codex AutomationsでAIに毎日のコンテンツ運用を任せる方法
Codex Automationsを使って、アクセス確認、記事改善、CTA改善、デプロイ、公開確認までを毎日の運用フローとして回す方法を解説します。
Claude Code × GCP Cloud Functions 完全ガイド|サーバーレス関数を爆速開発
GCP Cloud FunctionsをClaude Codeで効率化。HTTP/Pub/Sub/Firestoreトリガーの実装からローカルテスト・デプロイ自動化まで、Masaの実務経験をもとに実例コードで解説。