문제점 발견⭐️
5 day weather forecast - OpenWeatherMap
openweathermap.org
1) API 에서 제공되는 icon 과 dt_txt 간의 시간 불일치의 문제를 발견했다.
시간별 데이터를 보여줄 때 예를 들어, 오전 6시인데 d(낮☀️) 아이콘이 아닌 n(밤🌙) 아이콘이 나오는 경우가 발생했다.
이 문제점은 OpenWeatherAPI 에서 제공하는 icon 값은 UTC 기준으로 설정된 시간에 맞춰 제공되는데, API 에서 제공하는 dt_txt 값도 UTC 기준의 시간이었다. (Docs로 확인)
그래서 이를 변환하지 않아서 실제 한국 시간과 불일치하는 문제가 발생한 것이다.
해당 데이터를 화면에 업데이트하니 시간에 맞지 않는 icon 표시되는 문제
시도했던 방법 및 문제점
⚠️ 잘못된 문제 해결 시도: 문제 이해 부족으로 인한 혼란
1) 아이콘 매칭 관련 오해
이를 해결하기 위해
dt 값을 한국 시간으로 변환하기 위해 해당 메서드를 만들어서 dt_txt 에 포함된 시간을 한국 시간 기준으로 변환했다.
extension Date {
func toKST() -> Date {
let kstTimeZone = TimeZone(identifier: "Asia/Seoul")!
let seconds = TimeInterval(kstTimeZone.secondsFromGMT(for: self))
return self.addingTimeInterval(seconds)
}
}
이와 아이콘 매칭 로직은 별개라고 생각했다. 아이콘을 시간 변환 후 별도로 수정해야 한다고 생각하여 불필요한 추가 변환을 시도했다.
🤔: icon도 UTC 기반이니까 변환된 KST 시간에 맞게 아이콘을 매칭해야하나? sunset, sunrise 시간 추출해 아이콘 n/d를 적용해야겠다 >> 근본적인 문제를 보지 못하고 매우 바보 같은 생각을 했다..
✅ 하지만, API에서 제공하는 dt 값은 UTC 기준이며, 변환 후에 아이콘 매칭을 다시 할 필요 없음!
왜냐하면 단순히 변환된 KST 시간을 기준으로 보여주면 시간에 맞는 날씨정보(아이콘 포함)가 원래 제공되고 있었던 것임. 그저 시간만이 UTC 기준으로 보여주고 있어서 시간과 아이콘이 안 맞아 보였던 것뿐!!!!
즉, 아이콘은 원래 맞는 시간대에 제공되고 있었는데, UTC 기준으로 봤기 때문에 안 맞다고 착각한 것이다.. 정말 간단한 건데 왜 헷갈렸을까..
2) 현재 날씨(Current)도 변환이 필요하다고 착각
여기서 혼란이 오면서 current (현재 날씨) 도 변환이 필요하다고 오해했다.
🤔: 이것도 UTC 기준? current 현재 날씨도 시간 변환이 필요한가??
API에서 제공하는 dt 값이 UTC 기준이므로, 현재 날씨(current)도 UTC일 것이라고 착각했다. 따라서 current의 시간도 KST로 변환해야 한다고 생각한 것..!
✅ 하지만 실제로는 변환할 필요가 없다!
current 데이터는 API 에서 사용자의 현지 시간 기준으로 제공된다. 즉, current는 이미 올바른 시간대이므로 따로 변환할 필요가 없다. 변환이 필요한 것은 오직 Forecast Weather(예보 데이터) 뿐!
3) dtTxt 변환을 여러 번 수행하려고 한 문제
또한 dt (TimeInterval) 과 dt_txt(문자열 날짜)를 모두 변환해야 한다고 생각했다.
그래서 dtTxt 변환을 여러 번 수행하면서 불필요한 변형이 발생하고, 시간 오차가 생겼다.
✅ 해결 방법
사실 dtTxt 는 단순한 문자열이고, dt를 변환한 후 포맷팅하면 같은 값을 얻을 수 있다. 그래서 dt 만 변환해서 사용하기로 결정했다.
dtTxt는 삭제하고 dt를 KST 로 변환한 후, 필요한 포맷으로 문자열을 출력하는 방식으로 수정했다. 이 과정에서 처리 방식이 매우 깔끔하고 효율적으로 수정되었다.
문제 해결
1) 날짜 포맷팅 후 문자열 반환을 사용
- dtTxt를 변환하는 대신, dt 값을 변환하여 직접 사용하도록 변경. (dt → Date → String)
- Date 익스텐션을 활용하여 KST 변환 및 문자열 포맷팅을 간결하게 처리
Date Extension: 해결 방법 적용 코드
extension Date {
public func toKST() -> Date {
let kstTimeZone = TimeZone(identifier: "Asia/Seoul")!
let seconds = TimeInterval(kstTimeZone.secondsFromGMT(for: self))
return self.addingTimeInterval(seconds)
}
public var summary: String {
return toString("yyyy-MM-dd HH:mm:ss")
}
public var shortTime: String {
return toString("HH:mm")
}
// MARK: - Date -> String
public func toString(_ dateFormat: String) -> String {
return DateFormatter
.convertToKoKR(dateFormat: dateFormat)
.string(from: self)
}
}
extension DateFormatter {
public static func convertToKoKR(dateFormat: String) -> DateFormatter {
let dateFormatter = createKoKRFormatter()
dateFormatter.dateFormat = dateFormat
return dateFormatter
}
}
private func createKoKRFormatter() -> DateFormatter {
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "ko_KR")
dateFormatter.timeZone = TimeZone(abbreviation: "KST")
return dateFormatter
}
ForecastWeather 구조체 적용: KST 날짜 활용 및 변환 활용
struct ForecastWeather: Codable {
let dt: Int
let main: WeatherMain
let weather: [Weather]
// ✅ dt(Int)를 Date로 변환
var dtDate: Date? {
return Date(timeIntervalSince1970: TimeInterval(dt))
}
// ✅ KST(한국시간) 변환
var kstDate: Date? {
return dtDate?.toKST()
}
// ✅ KST 기준으로 포맷된 문자열 반환
var kstString: String? {
return kstDate?.summary
}
// ✅ KST 기준으로 'HH:mm' 포맷된 시간 반환
var kstTime: String? {
return kstDate?.shortTime
}
}
이렇게 dt를 변환한 후 원하는 필요한 포맷으로 문자열을 출력해서 사용할 수 있다!
포맷된 문자열을 화면에 보여주면 한국 시간 기준으로 데이터를 처리할 수 있다.
2) hourly 데이터 변환 후, 현재 시간과 비교하여 가공 / 아이콘 표시
- hourly 데이터의 dt 값을 KST 기준으로 변환한 후, 현재 시간(KST 기준)과 비교
- 시간 필터링을 통해 향후 27시간의 날씨데이터를 추출
ForecastDate와 currentDate를 KST 변환 후 필터링을 해야 시간에 맞는 예보를 정확히 UI에 보여줄 수 있다 !
private func updateHourlyWeather(_ forecastData: ForecastWeatherResult) {
let currentDate = Date().toKST() // 현재 서울 시간
let calendar = Calendar.current
let futureDate = calendar.date(byAdding: .hour, value: 27, to: currentDate)!
// 데이터 가공
hourlyWeather = forecastData.list.filter { weather in
if let date = weather.kstDate {
return date > currentDate && date <= futureDate
}
return false
}
}
OpenWeatherMap에서 제공하는 날씨 아이콘 코드를 시스템 아이콘으로 적절히 변환하는 코드를 사용했다.
static func getSystemIconName(_ iconCode: String) -> String {
switch iconCode {
case "01d": return "sun.max.fill" // 맑은 낮
case "01n": return "moon.stars.fill" // 맑은 밤
case "02d", "02n": return "cloud.sun.fill" // 약간 흐림
case "03d", "03n": return "cloud.fill" // 흐림
case "09d", "09n": return "cloud.drizzle.fill" // 이슬비
case "10d", "10n": return "cloud.rain.fill" // 비
case "11d", "11n": return "cloud.bolt.fill" // 천둥번개
case "13d", "13n": return "snow" // 눈
case "50d", "50n": return "cloud.fog.fill" // 안개
default: return "cloud" // 기본값
}
}
icon 값은 시간 변환 후 그대로 적용하면 되기 때문에, 위의 메서드를 사용해 코드를 기반으로 해당 아이콘을 반환했다.
💬 느낀점
✅ Date 포맷팅을 적절히 활용하면, 변환을 깔끔하게 처리할 수 있음.
✅ 불필요한 변환을 여러 번 수행하는 것은 데이터 오류를 초래할 수 있음.
KST 변환과 date 포맷팅에 대해 이해하는 시간이 되었다! 역시 API를 정확하게 파악한 뒤 개발에 들어가는 것이 중요한 것 같다.
문제를 해결하고 난 후 슬픈 소식은 KST는 UTC보다 9시간 빠르기 때문에,
OpenWeatherAPI 에서는 3일간의 데이터가 오전 9시부터 제공되지만 서울 시간 기준으로 9시간 뒤인 18시부터 알 수 있다.. 역시 API 에서 제공하는 데이터가 내가 생각하는 방식대로 바로 맞춰지지 않아 번거로운 경우가 많다는 것을 다시 한번 깨달았다. (하지만 유료는 원하는 대로 가능!ㅎㅎ..)
'TIL✏️' 카테고리의 다른 글
[TIL] RxSwift: Subject 동작 시점 문제 (0) | 2025.05.19 |
---|---|
[TIL] MVVM 리팩토링: Combine 방식 (0) | 2025.02.11 |
[iOS] 라이프 사이클 관리 앱 (1) - 최종 프로젝트 시작, 프로젝트 기획 및 와이어프레임 (0) | 2024.06.04 |
[iOS] 알람 앱 (5) - 스톱워치 CoreData 적용하기 (1) | 2024.06.04 |
[iOS] 알람 앱 (4) - UIEditMenuInteraction과 UIPasteboard (3) | 2024.05.16 |