IOS/iOS

[iOS]UTC Time To Date (feat. TimeZone)

안녕하세요 오늘은 사이드 프로젝트를 하면서 저를 아주 고생시켯던 녀석을 정리해 보려고 합니다.

현재 제가 진행하고있는 사이드 프로젝트는 애플 날씨 기본어플인데요, API로 들어오는 데이터가 날씨쪽의 경우

시간과 관련된 정보는 timezone, timezone_offset, dt 이렇게 3가지가 들어오게 됩니다

날씨어플 API 요청시 Data 정보 (JSON)

  • 요청시 가져오는 데이터의 일부분입니다.
"lat": 37.5665,
    "lon": 126.978,
    "timezone": "Asia/Seoul",
    "timezone_offset": 32400,
    "current": {
        "dt": 1610112601,
        "sunrise": 1610059627,
        "sunset": 1610094589,
  • 아래는 데이터의 설명입니다.

Timezone

  • 말그대로 타임존의 명칭을 의미합니다.

Timezone_offset

자세한 설명은 여기를 참고해주세요 ㅎㅎ
https://en.wikipedia.org/wiki/List_of_UTC_time_offsets

 

List of UTC time offsets - Wikipedia

This is a list of the UTC time offsets, showing the difference in hours and minutes from Coordinated Universal Time (UTC), from the westernmost (−12:00) to the easternmost (+14:00). It includes countries and regions that observe them during standard time

en.wikipedia.org

  • 간혹 컴퓨터의 시간을 표시할때 UTC+09:00 과 같은 단어를 보셨을 겁니다 여기서 + 09:00은 기준시간에서 9시간이 차이나는 것을 의미합니다. 표시되는 단위는 분 이지만 계산할때는 초단위로 계산합니다 즉 1분 차이가나면 60초, 1시간은 3600초 를 의미합니다 

    간단히 예를 들면 한국의 Time Offset은 32400이고 독일 모스크바의 Time Offset은 10800입니다 계산을 해보면 
    32400 - 10800 = 21600이고 이것을 60(sec) * 60(min) = 1시간 = 3600이 되는데
    21600 / 3600 의 값은 6이 됩니다 따라서 독일과 한국의 시간차는 6시간이 나는 것입니다.  
  • 오프셋은 꼭 한시간 단위가 아니라 45분 30분이 될 수도 있습니다.
  • 보통 국가나 지역들마다 자신들이 사용하는 타임존에 대해 고유의 이름을 부여합니다. 예를들어 대한민국의 타임존은 KST(Korea Standard Time)이라고 불리웁니다. 따라서 KST = UTC+09:00 이 됩니다.

Dt

  • UTC 즉 GMT와 비슷한 의미로 1972년 세슘원자의 진동수에 기반한 국제 원자시를 기준으로 다시 지정된 시간대 입니다.

문제점

  • 날씨앱을 만들면서 간단하게 UTC to Date라는 검색으로 DateFormatter를 사용해서 시간을 얻었지만 한가지 문제점이 생겼습니다 타임존 설정을 따로 하지 않았기 때문에 기본으로 설정된 시간이 리턴되었고 나라별로 다른 타임존을 가지고 있는데 시간이 정상적으로 표시되지 않는 문제가 발생했습니다.
  • 사용자가 위치를 저장할때 개별적인 타임존이 필요하므로 그에따른 메서드를 수정해야 했습니다
  • 또한 모델을 설계할때 타임존이 필요없을 거라는 생각에( 이짧은생각 ㅜㅜ) 타임존을 추가해야 했습니다.

해결방안

  • 먼저 Date에 Extension을 작성해서 올바른 Date가 있다면 거기서 요일, 시간, 오후오전, 24시기준표시 등을 얻을수 있기 때문에 DateFormatter만 수정이 필요했습니다. 검색을 통해 알아보니 Timezone을 통해 offset을 설정할수 있었지만 무슨이유인지 모르겠지만 값이 생각대로 나오지 않았습니다. 
  • 그래서 여러번의 검색을 통해 아래와 같이 구현해두신 분을 찾을수 있었고 해결할수 있었습니다
  • timeIntervalSince1970
    1. 타임인터벌 값을 이용해서 현재의 시간을 구할수 있습니다 UTC0 부터의 값을 이용해 00:00 의 offset을 가진 Date를 구할수 있습니다
    2. 1번에서 구한 Date를 이용해서 timezone_offset을 통해 각 타임존을 기반으로 현재의 시간을 구할수 있습니다.

코드 예시

  • 아래의 코드는 클래스로 일단 UTC 값을 TimeInterval로 변환해 Date값을 얻고 원하는 포맷으로 변환하는 코드입니다. 한국의 Timezone Offset은 32400입니다
  • dt는 제가 API를 요청한 시간을 기준으로 했습니다.
class DateConverter {
    // API로 받아온 dt를 Date로 바꾸어 줍니다
    func convertingUTCtime(_ dt: String) -> Date {
        let timeInterval = TimeInterval(dt)!
        let utcTime = Date(timeIntervalSince1970: timeInterval)
        return utcTime
    }
}

extension Date {    
//Extension을 활용해 상황에 맞는 Date.method를 사용해줍니다. 

    func toString( dateFormat format: String ) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = format
        dateFormatter.timeZone = TimeZone.autoupdatingCurrent
        dateFormatter.locale = Locale.current
        return dateFormatter.string(from: self)
    }

    func toStringKST( dateFormat format: String ) -> String {
        return self.toString(dateFormat: format)
    }

    func toStringUTC(_ timezone: Int ) -> String {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "a h:m"
        dateFormatter.timeZone = TimeZone(secondsFromGMT: timezone)
        return dateFormatter.string(from: self)
    }
}

let time = c.convertingUTCtime("1610112601").toStringUTC(32400)

//출력  = "PM 10:30"

Timezone의 변화에 따른 시간변화

  • toString은 자동으로 현재위치의 타임존을 계산해주고 있구요, toStringUTC는 원하는 time offset을 주어서 계산한 결과입니다. 

주의사항

  • 제가 Date값과 timezone을 한번에 처리하고 싶었는데 그렇게 하니까 값이 정상적으로 받아지지 않았습니다 이유는 알수없지만 제가 한것과 같이 먼저 Date를 구하고 그다음에 포맷과 타임존을 넣으면 시간이 제대로 리턴되었습니다. 혹시 잘되지 않으시는 분은 저렇게 똑같이 해보시면 잘 될거에요