Swift의 시간대 헛소리

13168 단어 swiftiosbeginners

그리고 그들이 당신을 미치게 만드는 방법


Calendar와 함께 작업하는 것이 불가피한 때가 옵니다. 때로는 쉬울 수도 있지만 매우 까다로울 수 있으니 주의하세요 😅

그럼 재미있게 즐겨봅시다 👍

서로 다른 두 값Date을 비교해야 한다고 가정합니다.

let date1 = Date(timeIntervalSince1970: 0) // 1970-01-01 00:00:00 
let date2 = Date(timeIntervalSince1970: 60 * 60 * 24) // 1970-01-02 00:00:00 

func compareDates(date1: Date, date2: Date){
    switch date1 {
    case date2:
        print("date1 and date2 represent the same point in time")
    case ...date2:
        print("date1 is earlier in time than date2")
    case date2...:
        print("date1 is later in time than date2")
    default:
        return
    }
}
compareDates(date1: date1, date2: date2)


우리가 가정하듯이 결과는 "date1 is earlier in time than date2" 입니다. 멋진! 😃

같은 날이지만 다른TimeZone 값을 사용하고 하루의 시작을 비교하려는 경우 어떻게 됩니까? (당신만이 왜 그것이 필요한지 대답할 수 있지만, 당신이 그렇게 한다고 가정하십시오 😅)

예를 들어 1971년에 베를린이나 뉴욕이 처음으로 설날을 기념했는지 알고 싶습니다.

...
func startOfDayIn(date: Date, timeZone: TimeZone) -> Date {
    var calendar = Calendar.current
    calendar.timeZone = timeZone
    return calendar.startOfDay(for: date)
}

let date = Date(timeIntervalSince1970: 60 * 60 * 24 * 365) // 1971-01-01 00:00:00
let timeZone1 = TimeZone(secondsFromGMT: 60 * 60 * 1)! // Berlin
let start1 = startOfDayIn(date: date, timeZone: timeZone1)
let timeZone2 = TimeZone(secondsFromGMT: 60 * 60 * -8)! // New York City
let start2 = startOfDayIn(date: date, timeZone: timeZone2)

compareDates(date1: start1, date2: start2)


쉬웠어요 😁 결과적으로..

무엇을 기다립니다?? "date1 is later in time than date2" 😳🤯😱 그게 어떻게 가능해? 베를린의 하루는 뉴욕의 하루보다 일찍 시작했어야 했는데 "date1 is earlier in time than date2"!!!

그럼 이것을 조사해 봅시다. 🧐

먼저 몇 가지 startTimes를 인쇄하여 비교하겠습니다. 우리는 1월 1일을 사용했기 때문에 날짜가 1970년 이전이기 때문에 문제가 되지 않는다고 확신할 수 있습니다.

(-12...12).reversed().forEach { deviation in
    let timeZone = TimeZone(secondsFromGMT: 60 * 60 * deviation)!
    let start = startOfDayIn(date: date, timeZone: timeZone)

    print(start, "| UTC\(deviation >= 0 ? "+" : "")\(deviation)")
}


이는 다음 목록을 제공합니다.


날짜
시간대



1970-12-31 12:00:00 +0000
UTC+12

1970-12-31 13:00:00 +0000
UTC+11

1970-12-31 14:00:00 +0000
UTC+10

1970-12-31 15:00:00 +0000
UTC+9

1970-12-31 16:00:00 +0000
UTC+8

1970-12-31 17:00:00 +0000
UTC+7

1970-12-31 18:00:00 +0000
UTC+6

1970-12-31 19:00:00 +0000
UTC+5

1970-12-31 20:00:00 +0000
표준시+4

1970-12-31 21:00:00 +0000
UTC+3

1970-12-31 22:00:00 +0000
UTC+2

1970-12-31 23:00:00 +0000
UTC+1

1971-01-01 00:00:00 +0000
표준시+0

1970-12-31 01:00:00 +0000
UTC-1
왜 우리는 다시 1970년으로 돌아갔습니까??

1970-12-31 02:00:00 +0000
UTC-2

1970-12-31 03:00:00 +0000
UTC-3

1970-12-31 04:00:00 +0000
UTC-4

1970-12-31 05:00:00 +0000
UTC-5

1970-12-31 06:00:00 +0000
UTC-6

1970-12-31 07:00:00 +0000
UTC-7

1970-12-31 08:00:00 +0000
UTC-8

1970-12-31 09:00:00 +0000
UTC-9

1970-12-31 10:00:00 +0000
UTC-10

1970-12-31 11:00:00 +0000
UTC-11

1970-12-31 12:00:00 +0000
UTC-12



좋습니다. UTC+0까지의 첫 번째 줄은 예상대로 표시됩니다. 그런데 왜 나머지는 잘못된 것입니까?

해결책은 다소 간단합니다. 전환이 너무 많거나 너무 적습니다TimeZone!

뉴욕 시간대UTC-8를 사용했을 때 날짜 값으로 "1971-01-01 00:00:00"를 사용했습니다. 그러나 이것은 UTC+0에 있습니다! UTC-8의 날짜는 실제로 "1970-12-31 18:00:00 -0800"입니다. startOfDay 를 호출하면 "1970-12-31 00:00:00 -0800" UTC+0 에 있는 "1970-12-31 08:00:00 +0000" 를 얻습니다.
이것은 결과가 실제로 정확하지만 우리의 기능은 🙈 그렇지 않다는 것을 의미합니다.

그럼 수정하자💪

func adjustedStartOfDayIn(date: Date, timeZone: TimeZone) -> Date {
    var calendar = Calendar.current
    calendar.timeZone = timeZone
    let correctDay = date.addingTimeInterval(TimeInterval(-calendar.timeZone.secondsFromGMT()))
    return calendar.startOfDay(for: correctDay)
}

let correctStart1 = adjustedStartOfDayIn(date: date, timeZone: timeZone1)
let correctStart2 = adjustedStartOfDayIn(date: date, timeZone: timeZone2)

compareDates(date1: correctStart1, date2: correctStart1)


이제 예상대로 "date1 is earlier in time than date2" 결과를 얻습니다. 😁
여기서 솔루션의 핵심은 date를 직접 사용하지 않고 특정 시간대와 UTC의 오프셋만큼 이동하여 사용하려는 시간대에서 startOfDay를 얻는다는 것입니다.

결론: 시간대를 혼동하지 마십시오!

전체 코드here를 찾을 수 있습니다.

좋은 웹페이지 즐겨찾기