[TIL] .dateDecodingStrategy

박주하·2025년 6월 27일

.dateDecodingStrategy


  • .dateDecodingStrategyJSONDecoder에서 날짜(Date)를 어떤 형식으로 파싱할지 정하는 옵션
  • Swift의 Codable을 사용할 때 Date 타입이 포함된 JSON을 자동으로 파싱할 수 있도록 도와주는 설정

{
  "title": "할 일",
  "dueDate": "2025-06-21T14:00:00Z"
}

이런 JSON을 디코딩하려고 하는데,

struct Todo: Codable {
    let title: String
    let dueDate: Date
}

모델을 이렇게 만들면, Swift는 Date를 어떻게 파싱할지 모르기 때문에 에러가 발생함.
→ 이걸 해결해주는 게 바로 .dateDecodingStrategy❗️


1. 사용 방법

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601  // 또는 .formatted(…) 등

let todo = try decoder.decode(Todo.self, from: jsonData)

2. 자주 쓰는 .dateDecodingStrategy 종류

전략설명예시
.iso8601ISO 8601 형식 지원"2025-06-21T14:00:00Z"
.secondsSince1970유닉스 초 기준1729564800
.millisecondsSince1970유닉스 밀리초 기준1729564800000
.formatted(DateFormatter)커스텀 포맷 직접 지정"2025년 06월 21일"
.custom((Decoder) throws -> Date)직접 파싱 로직 구현복잡한 케이스 대응

3. 예: DateFormatter 사용

// JSON
{
  "title": "회의",
  "dueDate": "2025-06-21 14:30:00"
}

// 파싱
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd HH:mm:ss"

let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
  • Date 형식에 맞게 DateFormatter를 세팅해줘야 정확히 파싱됨

4. 커스텀 파싱

🤔 날짜 형식이 여러 개 섞여 있다면??

  • JSONDecoder는 기본적으로 하나의 dateDecodingStrategy만 설정 가능
  • JSON에서 날짜 형식이 여러 개 섞여 있는 경우에는 custom 활용
[
  { "title": "회의", "date": "2025-06-21T14:30:00Z" },        // ISO 8601
  { "title": "점심", "date": "2025-06-21 12:00:00" },          // yyyy-MM-dd HH:mm:ss
  { "title": "리마인더", "date": "1729564800" }               // Unix timestamp (초)
]

JSON의 날짜가 이렇게 서로 다르게 생겼다면 다음처럼 custom 전략을 만들어서 처리❗️

let decoder = JSONDecoder()

decoder.dateDecodingStrategy = .custom { decoder in
    let container = try decoder.singleValueContainer()

    // 1. 숫자일 경우 (Unix Time)
    if let timestamp = try? container.decode(Double.self) {
        return Date(timeIntervalSince1970: timestamp)
    }

    // 2. 문자열일 경우
    let dateString = try container.decode(String.self)
    
    // 시도할 포맷 배열
    let formats = [
        "yyyy-MM-dd'T'HH:mm:ssZ",   // ISO 8601
        "yyyy-MM-dd HH:mm:ss",      // 일반 날짜+시간
        "yyyy/MM/dd",               // 다른 일반 날짜
        "yyyyMMdd"                  // 연속된 숫자
    ]
    
    let formatter = DateFormatter()
    formatter.locale = Locale(identifier: "en_US_POSIX")
    
    for format in formats {
        formatter.dateFormat = format
        if let date = formatter.date(from: dateString) {
            return date
        }
    }

    throw DecodingError.dataCorruptedError(
        in: container,
        debugDescription: "지원하지 않는 날짜 형식: \(dateString)"
    )
}
  • .custom 전략을 활용하면 다양한 날짜 형식을 유연하게 처리 가능
  • DateFormatter 여러 개를 순서대로 시도해보고, 처리 가능한 첫 번째 포맷으로 파싱
  • 새로운 형식이 추가되더라도 formats 배열만 수정하면 됨
  • 이 방식은 API 서버에서 날짜 형식이 불안정할 때 매우 유용

💡 날짜 인코딩(dateEncodingStrategy)도 가능

  • JSONEncoder에서 Date 타입을 어떤 형식으로 JSON 문자열로 바꿀지 지정하는 옵션
  • 즉, Swift 객체 → JSON으로 인코딩할 때 Date를 어떻게 문자열로 표현할지

0개의 댓글