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는 어떤 날짜 구성 요소를 반복할지 자동으로 결정하고(범위가 한 달 이내인 경우 월이 한 번 표시됨), 구분 기호와 단어 순서를 지역화합니다. 두 개의 서식 지정된 날짜를 수동으로 연결하는 것과 달리, 이 클래스는 언어의 문법 규칙을 고려합니다. 이 클래스는 iOS 8 및 macOS 10.10부터 사용할 수 있습니다.

주요 내용

  • DateIntervalFormatter — 날짜 범위 서식 지정을 위한 Foundation 클래스 (iOS 8+)
  • 자동 그룹화 — 반복 구성 요소(월, 년)가 한 번 표시됨
  • 지역화된 구분 기호 — 문법 규칙 고려: “부터” (한국어), 대시 (영어)
  • 다섯 가지 날짜 스타일 — .none, .short, .medium, .long, .full을 범위의 각 끝에 적용
  • 네 가지 시간 스타일 — 범위의 시간 부분에 대한 동일한 세부 수준

DateIntervalFormatter란?

DateIntervalFormatter는 Foundation에서 Formatter의 하위 클래스로, DateInterval 객체(두 날짜 사이의 범위)를 받아 해당 범위를 설명하는 지역화된 문자열을 반환합니다. 예를 들어, 2024년 7월 21일부터 25일까지의 범위의 경우 ko_KR에서는 “2024년 7월 21–25일”이 됩니다. 이 클래스는 반복 요소를 지능적으로 그룹화합니다: 두 날짜가 같은 월에 있으면 월 이름이 한 번 표시됩니다.

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는 범위를 형성하는 두 날짜를 분석하고 로케일을 고려하여 최적의 문자열 표현을 선택합니다. 이 클래스는 날짜 구성 요소(년, 월, 일)를 비교하고 그룹화 결정을 내립니다: 년이 같으면 한 번 표시, 월이 같으면 한 번 표시, 일이 다르면 일 범위가 표시됩니다.

범위ko_KR
하루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일의 경우: 년 일치, 월 일치, 일 다름 → 월이 한 번 표시되고, 일은 각 날짜에 대해 표시됩니다.

중요 참고 사항: DateIntervalFormatter는 API를 통한 구분 기호 사용자 지정을 지원하지 않습니다. 구분 기호는 로케일에 의해 결정되며 재정의할 수 없습니다. 비표준 구분 기호가 필요한 경우(예: “부터” 대신 “까지”), DateFormatter를 사용하여 각 날짜를 수동으로 서식 지정하고 사용자 지정 구분 기호로 문자열을 연결해야 합니다.

간격 서식 지정 스타일

DateIntervalFormatter는 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은 두 개의 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는 단일 날짜에만 사용하고, 문자열 연결을 통해 두 개의 서식 지정된 날짜를 결합하는 데 사용하지 마십시오. 구분 기호 지역화가 손실됩니다.

에지 케이스: DateIntervalFormatter는 개방형 간격(종료 날짜 없음)을 지원하지 않습니다. 범위의 끝을 알 수 없는 경우(예: “7월 21일부터”), “부터”와 함께 DateFormatter를 사용합니다. 또한 DateIntervalFormatter는 다른 날짜에 대한 시간 지정을 지원하지 않습니다. 시간은 각 날짜에 개별적으로 적용되며, 짧은 간격에서는 중복될 수 있습니다.

자주 묻는 질문

DateIntervalFormatter란?

DateIntervalFormatter는 날짜 범위를 지역화된 문자열로 서식 지정하는 Foundation 클래스입니다. iOS 8부터 사용 가능하며, 반복 구성 요소(월, 년)를 자동으로 그룹화하고 언어에 맞는 구분 기호를 선택합니다.

DateIntervalFormatter는 어떻게 날짜를 그룹화하나요?

구성 요소를 비교 년에서 일 순서로 비교합니다. 년이 일치하면 한 번 표시, 월이 일치하면 한 번 표시, 다른 일은 범위로 표시됩니다. 이렇게 하면 “2024년 7월 21일 – 2024년 7월 25일” 대신 “2024년 7월 21–25일”이 됩니다.

범위 구분 기호를 변경할 수 있나요?

아니요, 구분 기호는 로케일에 의해 결정되며 API를 통해 사용자 지정할 수 없습니다. 사용자 지정 구분 기호(예: “부터” 대신 “까지”)가 필요한 경우, 각 날짜를 별도의 DateFormatter로 서식 지정하고 수동으로 문자열을 연결하세요.

DateIntervalFormatter와 DateFormatter의 차이점은?

DateIntervalFormatter는 날짜 범위(두 날짜)를 구성 요소 그룹화와 함께 하나의 단위로 서식 지정합니다. DateFormatter는 단일 날짜를 서식 지정합니다. 범위의 경우 항상 DateIntervalFormatter를 사용하세요. 올바른 구분 기호 지역화를 제공합니다.

다른 연도의 간격을 서식 지정하는 방법은?

자동으로 — DateIntervalFormatter가 연도 차이를 감지하고 양쪽 끝에 전체 날짜를 표시합니다: “2024년 12월 25일 – 2025년 1월 5일”. 추가 구성이 필요하지 않으며, dateStyle만 설정하면 됩니다.

요약

  • DateIntervalFormatter — 날짜 범위 서식 지정 전용 클래스 (iOS 8+)
  • 자동 그룹화 — 반복 구성 요소(년, 월)가 전체 범위에 대해 한 번 표시됨
  • 지역화된 구분 기호 — “부터” (한국어), “bis” (독일어) 자동 선택
  • 날짜 및 시간 스타일 — .none, .short, .medium, .long, .full 조합을 범위의 각 끝에 적용
  • 기간에는 부적합 — 기간 계산에는 DateComponentsFormatter 사용
  • 사용자 지정 구분 기호 불가 — 비표준 경우 수동 서식 지정 필요
  • DateInterval과 통합 — DateInterval 구조체는 contains 및 intersection 확인 제공

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기