Today I Learn

Swift - 날짜 설정 DateFormmater VS Date.FormatStyle

Goniii 2025. 3. 27. 17:55

'1998-07-02' 형태의 Json 데이터(String)를 변형하여 'June 26, 1997'(String) 형태로 표시하려고 한다

1. DateFormmater

  • DateFormatter는 Foundation에서 제공하는 클래스로 날짜를 문자열로 변환하거나 반대로 변환하는 기능을 한다
  1. String 값을 dateFormmater를 이용하여 Date 타입으로 변환
  2. Date 타입의 dateStyle, locale을 설정하여 Date → String 타입으로 변환
    init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // '1998-07-02' 형태로 되어있는 Json 데이터를 변형하여 'June 26, 1997' 형태로 표시
        let releaseString = try container.decode(String.self, forKey: .releaseDate)
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        
        // String -> Date 타입으로 변환
        guard let date = dateFormatter.date(from: releaseString) else {
            self.releaseDate = "Formmating Error"
            return
        }
        
        // '1998-07-02'-> 'June 26, 1997' 변환 ('en_US' Locale 사용)
        dateFormatter.dateStyle = .medium
        dateFormatter.locale = Locale(identifier: "en_US")
        self.releaseDate = dateFormatter.string(from: date)
    }

→ dateFormmater의 dateStyle을 .medium으로 설정했다. 이게 뭘까?

 

dateStyle: DateFormatter.Style

  • https://developer.apple.com/documentation/foundation/dateformatter/style
  • DateFormatter에서 사용하는 enum 타입으로 날짜와 시간을 설정하는 속성
  • 날짜 및 시간 스타일의 형식은 Locale, 사용자 환경 설정 및 운영체제 버전에 따라 달라져서 정확하지 않음
  • 정확한 형식을 원하는 경우 이러한 enum 타입을 사용하면 안 됨
  • Case
    • .none: 스타일을 지정하지 않음
    • .short: 숫자로만 구성된 짧은 스타일(예: "11/23/37" 또는 "3:30 PM")
    • .medium: "1937년 11월 23일"이나 "오후 3시 30분 32초"와 같이 약어가 포함된 중간 스타일을 지정
    • .long: "1937년 11월 23일" 또는 "오후 3시 30분 32초 PST"와 같이 전체 텍스트가 포함된 긴 스타일
    • .full: “Tuesday, April 12, 1952 AD” or “3:30:42 PM”와 같이 모든 세부 정보가 포함된 전체 스타일

→ 현재 코드에서는 dateStyle을 .medium으로 지정했다

왜냐? 'June 26, 1997' 형식으로 Date를 변경하기 위해 Locale을 변경하는데 Locale을 변경할 때 Time 정보가 존재 하지 않으므로 제대로 Formatting되지 않음

따라서 Time을 표현하지 않는 .medium 타입으로 변경한 후 Locale을 변경해주는 것!

DateFormmater의 단점

  1. 성능 이슈
    • DateFormatter는 생성될 때마다 내부적으로 비용이 큰 초기화 작업을 수행함
    • 특히, dateFormat을 자주 변경하면 매번 새로운 객체를 생성하는 것과 동일한 오버헤드 발생
  2. 로컬라이징 문제
    • dateFormat을 집적 문자열로 설정하면 언어 및 지역에 따라 포맷이 깨질 가능성 있음
  3. 타입 안전성 부족
    • dateFormat은 문자열이므로, 오타가 있어도 컴파일러가 체크해주지 않음
    • “YYYY’ 와 ‘yyyy’의 차이처럼 잘못된 포맷을 사용하면 예상치 못한 오류 발생 가능

 

2. Date.FormatStyle

  • Swift 5.5(iOS 15, macOS 12)부터 도입된 타입 안전한 날짜 포맷 방식
  • DateFormmater의 단점을 해결하기 위해 등장함

https://developer.apple.com/documentation/foundation/date/formatstyle

    init(from decoder: any Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)

        // '1998-07-02' 형태로 되어있는 Json 데이터를 변형하여 'June 26, 1997' 형태로 표시
        let releaseString = try container.decode(String.self, forKey: .releaseDate)
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "yyyy-MM-dd"
        
        // String -> Date 타입으로 변환
        guard let date = dateFormatter.date(from: releaseString) else {
            self.releaseDate = "Formmating Error"
            return
        }
        
        // '1998-07-02'-> 'June 26, 1997' 변환
        self.releaseDate = date.formatted(date: .abbreviated, time: .omitted)
    }

formatted(date: time:) 메서드 분석

1. date: 파라미터 (날짜 포맷 스타일)

옵션 설명 예제 출력 (2025년 3월 26일 기준)
.omitted 날짜 관련 구성 요소가 표현되지 않은 날짜 스타일입니다. (날짜 생략)
.numeric 월, 일, 연도 구성 요소를 숫자 값으로 표현한 날짜 스타일입니다. "3/26/2025"
.abbreviated 공간이 제한된 애플리케이션을 위해 일부 구성 요소가 축약된 날짜 스타일입니다. "Mar 26, 2025"
.long 전체 월, 일, 연도 구성 요소를 표현한 확장된 날짜 스타일입니다. "March 26, 2025"
.complete 모든 구성 요소가 표현된 날짜 스타일입니다. "Wednesday, March 26, 2025"
let now = Date()
print(now.formatted(date: .omitted, time: .standard)) // "2:30 PM"
print(now.formatted(date: .numeric, time: .omitted)) // "3/26/2025"
print(now.formatted(date: .abbreviated, time: .omitted)) // "Mar 26, 2025"
print(now.formatted(date: .long, time: .omitted)) // "March 26, 2025"
print(now.formatted(date: .complete, time: .omitted)) // "Wednesday, March 26, 2025"

 

2. time: 파라미터 (시간 포맷 스타일)

  • time 매개변수는 시간을 어떻게 표현할지를 지정함
옵션 설명 예제 출력 (오후 2시 30분 기준)
.omitted 시간 관련 구성 요소가 표현되지 않은 시간 스타일입니다. (시간 생략)
.shortened 시간, 분, 일 단위의 구성 요소만 표현된 단축된 시간 스타일입니다. "2:30 PM"
.standard 시간대를 제외한 모든 구성 요소를 나타낸 시간 스타일입니다. "2:30:45 PM"
.complete 모든 구성 요소가 표현된 시간 스타일입니다. "2:30:45 PM Coordinated Universal Time"
let now = Date()
print(now.formatted(date: .numeric, time: .omitted)) // "3/26/2025"
print(now.formatted(date: .numeric, time: .shortened)) // "3/26/2025, 2:30 PM"
print(now.formatted(date: .numeric, time: .standard)) // "3/26/2025, 2:30:45 PM"
print(now.formatted(date: .numeric, time: .complete)) // "3/26/2025, 2:30:45 PM Coordinated

 

Date.FormatStyle의 단점

  1. String → Date를 지원하지 않음
    • Formatter가 아니라 타입 안전성을 강화한 구조체(struct) 기반 API
    • 변환 방향(Date → String)을 명확하게 제한하여 실수로 인한 오류를 줄이고 성능을 최적화하려는 의도를 가짐
    • String → Date로 변환하려면 DateFormatter를 사용해야 함

 

DateFormatter VS Date.FormatStyle 차이점 정리

특징 DateFormatter FormatStyle
타입 클래스 (DateFormatter) 구조체 (FormatStyle)
성능 초기화 비용이 큼, 캐싱 필요 더 가볍고 빠름
타입 안전성 문자열 기반 (dateFormat)으로 오류 발생 가능 메서드 체이닝 방식으로 타입 안전함
로컬라이징 Locale을 수동으로 설정해야 함 자동 로컬라이징 지원
사용성 dateFormat을 직접 지정해야 함 .year().month().day()처럼 직관적
날짜 변환 formatter.string(from:), formatter.date(from:) .formatted(), Date(_:strategy:)
가독성 문자열 기반이라 가독성이 낮음 체이닝 방식으로 직관적

 

Date.FormatStyle은 DateFormatter보다 빠르고, 안전하고, 직관적인 API이다.

formatted(date:time:)를 활용하면 날짜와 시간을 간단하게 변환할 수 있다.

iOS 15 미만을 지원해야 한다면 DateFormatter를 사용해야 하지만, iOS 15 이상을 지원하는 프로젝트에서는 DateFormatter보다 Date.FormatStyle을 적극 활용하는 것이 좋다.

String -> Date 변환이 필요하면 DateFormatter를 사용해야 한다