DateIntervalFormatter — 日付間隔書式設定の基礎

著者: IT Sectr 公開日: 2026-07-13 読了時間: 11 分

DateIntervalFormatterは、iOSおよびmacOSのFoundationクラスで、日付範囲をローカライズされた文字列にフォーマットするために設計されています:“2024年7月21〜25日”、“2024年7月21日から25日”、または“Jul 21–25, 2024”など。Apple Developer Documentation, 2024によると、DateIntervalFormatterは、どの日付コンポーネントを繰り返すかを自動的に判断し(範囲が1か月以内の場合は月が1回表示されます)、区切り文字と語順をローカライズします。2つのフォーマットされた日付を手動で連結するのとは異なり、このクラスは言語の文法ルールを考慮します。このクラスはiOS 8およびmacOS 10.10以降で利用可能です。

主要ポイント

  • DateIntervalFormatter — 日付範囲をフォーマットするFoundationクラス(iOS 8+)
  • 自動グループ化 — 繰り返しコンポーネント(月、年)は1回表示
  • ローカライズされた区切り文字 — 文法ルールを考慮:“から”(日本語)、ダッシュ(英語)
  • 5つの日付スタイル — .none、.short、.medium、.long、.fullを範囲の両端に適用
  • 4つの時刻スタイル — 範囲の時刻部分に同様の詳細レベル

DateIntervalFormatterとは?

DateIntervalFormatterは、FoundationのFormatterのサブクラスで、DateIntervalオブジェクト(2つの日付間の範囲)を受け取り、その範囲を説明するローカライズされた文字列を返します。たとえば、2024年7月21日から25日までの範囲の場合、ja_JPでは“2024年7月21〜25日”となります。このクラスは繰り返し要素をスマートにグループ化します。両方の日付が同じ月にある場合、月名は1回だけ表示されます。

DateIntervalFormatterの主な価値は、範囲の文法を自動的に処理することです。手動でフォーマットする場合、開発者は開始/終了の月/年を比較し、区切り文字(ダッシュ、“から”、“bis”)を選択し、活用形を処理する必要があります。DateIntervalFormatterはCLDR(Common Locale Data Repository)データに基づいてこれを自動的に行い、国際化アプリケーションのバグを削減します。特に複雑な文法を持つ言語で効果的です。

Unicode CLDR v44(2024)によると、日付間隔の書式設定ルールは言語によって大きく異なります。ドイツ語は“bis”(21.–25. Juli 2024)、フランス語は“au”(du 21 au 25 juillet 2024)、日本語はハイフン(2024 Jul 21–25)を使用します。DateIntervalFormatterは、開発者の追加コードなしでこれらすべてのバリエーションをカバーします。

FoundationにおけるDateIntervalFormatterの仕組み

動作原理 DateIntervalFormatterは、範囲を形成する2つの日付を分析し、ロケールを考慮して最適な文字列表現を選択します。このクラスは日付コンポーネント(年、月、日)を比較し、グループ化の判断を行います:年が同じ場合は1回表示、月が同じ場合は1回表示、日が異なる場合は日付範囲が表示されます。

範囲ja_JP
1日2024年7月21日
月内2024年7月21〜25日
異なる月2024年7月21日 – 8月5日
異なる年2024年12月25日 – 2025年1月5日
時刻あり2024年7月21日 14:30〜16:45

グループ化ロジックはCLDRテンプレートに基づいて実装されています。フォーマッタは各日付コンポーネント(Calendar.Component:year、month、day)の等価性を大きいものから小さいものへ順にチェックします。コンポーネントが異なると、それより小さいすべてのコンポーネントが両方の日付に対して表示されます。たとえば、7月21〜25日の場合:年が一致、月が一致、日が異なる → 月は1回表示、日は各日付に対して表示されます。

重要な注意点: DateIntervalFormatterはAPIを介した区切り文字のカスタマイズをサポートしていません。区切り文字はロケールによって決定され、上書きできません。標準的でない区切り文字が必要な場合(たとえば、“から”の代わりに“〜”)、DateFormatterを使用して各日付を手動でフォーマットし、カスタム区切り文字で文字列を連結する必要があります。

間隔書式設定スタイル

DateIntervalFormatterは2つのスタイルセットを提供します:dateStyleとtimeStyle — 範囲の両端に適用されます。これらのスタイルはDateFormatterと同様に機能します:.noneはコンポーネントを非表示に、.shortは短い形式(2024/07/21)、.medium(2024年7月21日)、.long(2024年7月21日)、.full(2024年7月21日日曜日)を提供します。dateStyleとtimeStyleを組み合わせることで、異なる詳細レベルを実現できます。

スタイル組み合わせ例

  • dateStyle = .medium, timeStyle = .none — 日付のみ:“2024年7月21〜25日”
  • dateStyle = .short, timeStyle = .short — 日付と時刻:“2024/07/21 14:30 – 2024/07/25 16:45”
  • dateStyle = .none, timeStyle = .short — 時刻のみ:“14:30〜16:45”(日付が同じ場合)
  • dateStyle = .long, timeStyle = .none — 長い日付:“2024年7月21〜25日”
  • dateStyle = .full, timeStyle = .short — 完全形式:“2024年7月21日日曜日 – 2024年7月25日木曜日”

重要: dateStyleとtimeStyleは範囲の両端に均等に適用されます。開始と終了で異なるスタイルを設定することはできません(例:開始に.medium、終了に.short)。異なるスタイルが必要な場合は、各日付を個別のDateFormatterでフォーマットし、結果を連結する必要があります。

swift
import Foundation

let formatter = DateIntervalFormatter()

// さまざまなスタイルの組み合わせ
let startDate = Date()
let endDate = Date().addingTimeInterval(345600) // +4日
let interval = DateInterval(start: startDate, end: endDate)

// 日付のみ、ミディアム形式
formatter.dateStyle = .medium
formatter.timeStyle = .none
print("日付のみ:\(formatter.string(from: interval))")

// 時刻付きショート形式
formatter.dateStyle = .short
formatter.timeStyle = .short
print("時刻付きショート:\(formatter.string(from: interval))")

// 完全形式
formatter.dateStyle = .full
formatter.timeStyle = .none
print("完全な日付:\(formatter.string(from: interval))")

SwiftでのDateIntervalFormatter:例

基本的な使用方法 DateIntervalFormatterは、インスタンスを作成し、スタイルを設定し、string(from:)を呼び出します。このメソッドはstartとendプロパティを持つ構造体DateIntervalを受け入れます。DateIntervalは2つのDate値から作成するか、Duration(iOS 16+)で初期化できます。フォーマット後、結果は追加処理なしでUI表示に使用できます。

swift
import Foundation

let calendar = Calendar.current
let now = Date()

// 特定の間隔例
let examples: [(title: String, start: Date, end: Date)] = [
    (
        "2-hour event",
        now,
        now.addingTimeInterval(7200)
    ),
    (
        "Week-long vacation",
        now,
        now.addingTimeInterval(604800)
    ),
    (
        "Cross-year period",
        calendar.date(from: DateComponents(
            year: 2024, month: 12, day: 25
        ))!,
        calendar.date(from: DateComponents(
            year: 2025, month: 1, day: 5
        ))!
    )
]

let intervalFormatter = DateIntervalFormatter()
intervalFormatter.dateStyle = .medium
intervalFormatter.timeStyle = .short

for (title, start, end) in examples {
    let interval = DateInterval(start: start, end: end)
    let result = intervalFormatter.string(from: interval)
    print("\(title): \(result)")
}

// Calendar経由のフォーマット(iOS 16+)
if let nextWeek = calendar.date(
    byAdding: .day, value: 7, to: now
) {
    let weekInterval = DateInterval(start: now, end: nextWeek)
    print("次の7日間:\(intervalFormatter.string(from: weekInterval))")
}

DateIntervalFormatterとカレンダー予約: 予約アプリケーション(ホテル、チケット)では、日付間隔は重要なUI要素です。DateIntervalFormatterは年をまたがる間隔(例:12月28日から1月3日)を正しく処理し、各日付の月と年を個別にグループ化します。このようなシナリオでは、dateStyle = .mediumとtimeStyle = .noneの使用をお勧めします。時刻なしの日付に最も読みやすい形式です。

swift
import Foundation

let formatter = DateIntervalFormatter()
formatter.dateStyle = .long
formatter.timeStyle = .none

// 予約例
struct Booking {
    let checkIn: Date
    let checkOut: Date

    var formattedInterval: String {
        let interval = DateInterval(start: checkIn, end: checkOut)
        return formatter.string(from: interval)
    }
}

let booking = Booking(
    checkIn: calendar.date(from: DateComponents(
        year: 2024, month: 7, day: 21
    ))!,
    checkOut: calendar.date(from: DateComponents(
        year: 2024, month: 7, day: 25
    ))!
)
print("予約:\(booking.formattedInterval)")

// 異なるロケールでの使用
let enFormatter = DateIntervalFormatter()
enFormatter.dateStyle = .medium
enFormatter.timeStyle = .none
enFormatter.locale = Locale(identifier: "en_US")
print("英語:\(enFormatter.string(from: interval))")

DateIntervalとDateIntervalFormatterの比較: DateIntervalは日付範囲(開始と終了)を表す構造体です。DateIntervalFormatterはこの構造体を文字列に変換するフォーマッタです。DateIntervalはcontains(Date)チェックとintersection(with:)もサポートしており、予約ロジック(日付の重複チェック)に役立ちます。

日付間隔のローカライズ

DateIntervalFormatterはlocaleプロパティを介して出力をローカライズします。デフォルトではLocale.current(デバイスのロケール)が使用されます。別の言語で間隔を表示するには(例:日本語インターフェースで英語コンテンツ)、localeを明示的に設定します。DateFormatterとは異なり、DateIntervalFormatterはサーバー側データにlocaleを設定する必要はありません。常に内部のCLDRベースのグループ化ロジックを使用します。

日付間隔の書式設定における言語の違いは、単一の日付よりもはるかに複雑です。日本語は“から”を使用します:7月21日から25日。英語は単純なダッシュを使用します:Jul 21–25。フランス語は“au”:du 21 au 25 juillet。ドイツ語は数字の後にピリオドとダッシュ:21.–25. Juli。DateIntervalFormatterはこれらすべてのバリエーションをカバーします。

swift
import Foundation

let formatter = DateIntervalFormatter()
formatter.dateStyle = .medium
formatter.timeStyle = .none

let start = Date()
let end = Date().addingTimeInterval(259200) // +3日
let interval = DateInterval(start: start, end: end)

// 異なるロケールの表示
let localeIds = ["ru_RU", "en_US", "de_DE", "fr_FR", "ja_JP", "zh_CN"]
for localeId in localeIds {
    formatter.locale = Locale(identifier: localeId)
    print("\(localeId): \(formatter.string(from: interval))")
}

// 時刻間隔のローカライズ
formatter.dateStyle = .none
formatter.timeStyle = .short

let todayStart = Date()
let todayEnd = Date().addingTimeInterval(3600)
let timeInterval = DateInterval(start: todayStart, end: todayEnd)

for localeId in ["ru_RU", "en_US", "de_DE"] {
    formatter.locale = Locale(identifier: localeId)
    print("\(localeId) 時刻:\(formatter.string(from: timeInterval))")
}

ローカライズの詳細: 日本語の場合、DateIntervalFormatterは長い形式で“から”を使用し、短い形式ではダッシュを使用します。形式の選択はコンテキストに依存します:予約リストには.medium、詳細ビューには.longまたは.fullを使用します。

他の日付フォーマッタとの比較

DateIntervalFormatterは、他のFoundationクラスではカバーされない日付範囲のフォーマットニッチを埋めます。DateFormatterは単一の日付、RelativeDateTimeFormatterは相対日付(前/後)、DateComponentsFormatterは期間(2時間30分)をフォーマットします。これらの各クラスは特定のタスクを解決し、互換性はありません。

クラス目的出力例
DateIntervalFormatter日付範囲2024年7月21〜25日
DateFormatter単一日付2024年7月21日
RelativeDateTimeFormatter相対時間3日前
DateComponentsFormatter期間2時間30分
ISO8601DateFormatterISO 8601形式2024-07-21T14:30:00Z

DateIntervalFormatterを使用するタイミング: UIでの日付範囲表示 — ホテル予約、イベント、日付フィルタリング、操作履歴。日付間の期間を計算するには、DateComponentsFormatterを使用します。DateIntervalFormatterは期間表示用に設計されていません。DateFormatterは単一の日付にのみ使用し、文字列連結による2つのフォーマット済み日付の結合には使用しないでください。区切り文字のローカライズが失われます。

エッジケース: DateIntervalFormatterはオープンエンドの間隔(終了日なし)をサポートしていません。範囲の終了が不明な場合(例:“7月21日から”)、“から”と共にDateFormatterを使用します。また、DateIntervalFormatterは異なる日の時刻指定をサポートしていません。時刻は各日付に個別に適用され、短い間隔では冗長に見える場合があります。

よくある質問

DateIntervalFormatterとは?

DateIntervalFormatterは、日付範囲をローカライズされた文字列にフォーマットするFoundationクラスです。iOS 8から利用可能で、繰り返しコンポーネント(月、年)を自動的にグループ化し、言語に適した区切り文字を選択します。

DateIntervalFormatterはどのように日付をグループ化しますか?

コンポーネントを比較 年から日へと比較します。年が一致すれば1回表示、月が一致すれば1回表示、異なる日は範囲として表示されます。これにより、“2024年7月21日 – 2024年7月25日”ではなく“2024年7月21〜25日”となります。

範囲の区切り文字を変更できますか?

いいえ、区切り文字はロケールによって決定され、APIを介してカスタマイズできません。カスタム区切り文字が必要な場合(例:“から”の代わりに“〜”)、各日付を個別のDateFormatterでフォーマットし、手動で文字列を連結してください。

DateIntervalFormatterとDateFormatterの違いは?

DateIntervalFormatterは日付範囲(2つの日付)をコンポーネントグループ化とともに1つの単位としてフォーマットします。DateFormatterは単一の日付をフォーマットします。範囲には常にDateIntervalFormatterを使用してください。正しい区切り文字のローカライズが提供されます。

異なる年の間隔をフォーマットするには?

自動的に — DateIntervalFormatterが年の違いを検出し、両端に完全な日付を表示します:“2024年12月25日 – 2025年1月5日”。追加設定は不要で、dateStyleを設定するだけです。

まとめ

  • DateIntervalFormatter — 日付範囲のフォーマットに特化したクラス(iOS 8+)
  • 自動グループ化 — 繰り返しコンポーネント(年、月)は範囲全体で1回表示
  • ローカライズされた区切り文字 — “から”(日本語)、“bis”(ドイツ語)自動選択
  • 日付と時刻のスタイル — .none、.short、.medium、.long、.fullの組み合わせを範囲の両端に適用
  • 期間には不向き — 期間計算にはDateComponentsFormatterを使用
  • カスタム区切り文字不可 — 標準的でない場合は手動フォーマットが必要
  • DateIntervalとの統合 — DateInterval構造体はcontainsとintersectionチェックを提供

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください