平日を表示する:DateオブジェクトとIntl APIによるモダンな実装戦略
フロントエンド開発において、日付データから「平日か休日か」を判定し、それを適切にUIへ表示する処理は、予約システム、カレンダーアプリケーション、勤怠管理ツールなど、あらゆるビジネスアプリケーションで頻出する要件です。
単に「土日を除外する」というロジックは一見単純ですが、祝日の考慮、国際化対応、そしてアクセシビリティを考慮した実装となると、考慮すべきエッジケースが急激に増大します。本記事では、JavaScriptの標準機能を用いた堅牢な実装方法から、実務で遭遇する課題への対応策までを網羅的に解説します。
DateオブジェクトとIntl.DateTimeFormatによる基本判定
JavaScriptで曜日を判定する最も標準的な方法は、`Date`オブジェクトの`getDay()`メソッドを使用することです。このメソッドは0(日曜日)から6(土曜日)の整数を返します。
平日判定のロジックは、「getDayの結果が0でも6でもない」という条件式で定義できます。しかし、実務ではこれに加えて「祝日」の判定が不可欠です。祝日は年ごとに変動するため、ハードコーディングは避け、外部ライブラリやAPIを利用するのが定石です。
また、曜日を文字列として表示する際には、`Intl.DateTimeFormat`を使用することを強く推奨します。これはブラウザのロケール設定に基づいて、自動的に「月曜日」「Mon」「Monday」といった適切な表記を生成してくれるため、国際化対応が容易になります。
サンプルコード:曜日と平日の判定ロジック
以下に、特定の日にちが平日かどうかを判定し、日本語で曜日を表示する汎用的な関数を示します。
/**
* 指定した日付が平日かどうかを判定し、曜日を返す関数
* @param {Date} date - 判定対象の日付
* @param {string[]} holidays - 祝日リスト(YYYY-MM-DD形式の配列)
* @returns {{isWeekday: boolean, dayName: string}}
*/
function getDayInfo(date, holidays = []) {
// 祝日判定(ISO文字列形式で比較)
const dateString = date.toISOString().split('T')[0];
const isHoliday = holidays.includes(dateString);
// 曜日取得 (Intl API)
const dayName = new Intl.DateTimeFormat('ja-JP', { weekday: 'long' }).format(date);
// 判定ロジック
const dayIndex = date.getDay();
const isWeekend = dayIndex === 0 || dayIndex === 6;
const isWeekday = !isWeekend && !isHoliday;
return {
isWeekday,
dayName,
isHoliday
};
}
// 使用例
const today = new Date();
const holidays = ['2023-12-25', '2024-01-01']; // 例
const result = getDayInfo(today, holidays);
console.log(`今日は${result.dayName}です。平日ですか?: ${result.isWeekday}`);
祝日データの管理と実務上の課題
実務において「祝日判定」を実装する際、最も頭を悩ませるのが「祝日データのソース」です。内閣府から提供されるCSVデータを利用するのが最も正確ですが、これを毎回フェッチするのは非効率です。
推奨されるアプローチは以下の3点です。
1. **バックエンドからの提供**: 祝日判定ロジックをバックエンド(API)に集約し、フロントエンドは「その日が営業日か否か」というフラグをAPIから受け取る構成にします。これにより、祝日法の改正があった場合でも、フロントエンドの改修なしで対応可能です。
2. **date-fns-tzやdate-fnsの活用**: `date-fns`のような軽量かつ強力なライブラリを使用し、日付操作の複雑さを隠蔽します。ただし、祝日判定については別途`date-holidays`のようなライブラリを組み合わせるのが一般的です。
3. **静的サイト生成(SSG)時の組み込み**: Next.jsなどで開発している場合、ビルド時に祝日データを取得してJSONとしてバンドルしておくことで、ランタイムのネットワーク負荷を軽減できます。
アクセシビリティとUI/UXの最適化
「平日を表示する」というUIにおいて、エンジニアが見落としがちなのが「色の使用」です。単に「土曜は青、日曜・祝日は赤」と色だけで表現すると、色覚多様性を持つユーザーには情報が伝わりません。
必ず「(土)」「(日)」というテキスト情報を添えるか、アイコンやラベルを併用するようにしてください。また、スクリーンリーダーを使用しているユーザーに対しては、`aria-label`属性を使用して「2023年10月10日 火曜日 祝日」のように、日付と曜日の情報を補完して読み上げられるように設計することが重要です。
パフォーマンスへの配慮
カレンダーUIのように一度に大量の日付を表示する場合、ループ内で毎回`new Intl.DateTimeFormat`をインスタンス化するのはパフォーマンスを低下させる原因となります。
// アンチパターン:ループ内で毎回インスタンス化
for (const date of dates) {
const formatter = new Intl.DateTimeFormat('ja-JP', { weekday: 'short' });
// ...
}
// 推奨:インスタンスをキャッシュする
const formatter = new Intl.DateTimeFormat('ja-JP', { weekday: 'short' });
const dayNames = dates.map(date => formatter.format(date));
このように、フォーマッタを再利用することで、メモリ消費を抑え、レンダリング速度を向上させることができます。フロントエンドスペシャリストとしては、こうした細かな最適化を積み重ねることが、アプリケーション全体のUX向上に直結することを忘れてはなりません。
実務アドバイス:タイムゾーンの罠
サーバーサイドとクライアントサイドで日付を扱う場合、必ず「タイムゾーン」を意識してください。`new Date()`は実行環境のローカルタイムゾーンに依存するため、サーバーから受け取ったUTCのISO文字列をそのまま`Date`に渡すと、日付がズレる(前日になってしまう)というバグが頻発します。
必ず`Date`オブジェクトを操作する前に、UTCからローカル時間への変換を厳密に行うか、`dayjs`や`date-fns`等のライブラリを使用してタイムゾーンを固定して扱う習慣をつけましょう。特に日本時間(JST)を扱う場合は、`+09:00`のオフセットを考慮した設計が必須です。
まとめ:保守性の高い平日判定の実装に向けて
平日を表示するという機能は、一見単純なようでいて、実は「正確な日付計算」「国際化」「アクセシビリティ」「パフォーマンス」「タイムゾーン管理」というフロントエンド開発の主要な要素が全て詰まった興味深いテーマです。
本記事で紹介した`Intl` APIの活用や、祝日データの分離管理、そしてアクセシビリティへの配慮を実践することで、単に「動く」だけでなく、「堅牢で保守性の高い」コードベースを維持することができます。
最後に、プロダクトの規模が大きくなるほど、日付に関するロジックは独自実装を避け、定評のあるライブラリや標準APIを正しく組み合わせる「賢い選択」が求められます。複雑な要件に直面した際は、常に「このロジックは将来的に変更される可能性があるか?」という視点を持ち、柔軟な設計を心がけてください。

コメント