일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- ViewBuilder
- 개발자 면접
- GeometryReader
- 스크롤 탭
- UIViewControllerTransitioningDelegate
- Swift Package Manager
- detect url
- scrolling tab
- 상단 탭바
- swift
- DataBinding
- ios
- url 관찰
- Side Menu
- 기존 앱
- transformation.map
- DevelopmentRegion
- UIPresentationController
- base64 변환
- url 추적
- development language
- pod install
- oberve url
- notifychanged
- convert base64
- swift #swift keychain #keychain 사용법
- Android
- Tuist
- List
- SwiftUI
- Today
- Total
버그 잡이
Swift - Date()는 왜 9시간 전의 날짜를 반환할까? 본문
문제의 발단
오늘 하루 동안 다시 보지 않기를 위해서
현재 시간에 1일을 더한 날짜를 저장하고
그 시간을 현재 시간과 비교하는 로직을 구현해야 했는데요.
관련해서 print문을 찍어보니 Date()가 9시간 전의 시간으로 출력되는 것을 확인했습니다.
// 현재 시간 (한국 시간 7월 28일 15시)
let currentDate = Date()
print("\(currentDate)") // 2024-07-28 06:04:34 +0000
왜 그럴까요?
원인은 TimeZone 때문입니다.
Date()는 기본적으로 UTC 기준으로 생성됩니다.
UTC는 한국 시간 보다 9시간 전의 시간입니다.
사실 UTC 기준으로 Date를 저장하고 UTC 기준으로 Date를 비교하면 문제 없습니다.
24시간 기준으로 한다면 말이죠.
둘 다 UTC 기준으로 값을 저장하고 비교하면 됩니다.
let currentDate = Date()
print("\(currentDate)") // 2024-07-28 06:07:46 +0000
let oneDayLater = Calendar.current.date(byAdding: .day, value: 1, to: currentDate)!
print("\(oneDayLater)") // 2024-07-29 06:07:46 +0000
하지만 오늘 하루 보지 않기의 기준이 24시간이 아닌 다음날 0시라면
TimeZone을 보다 유심히 봐야합니다.
DateFormatter로 가공하는 경우
아래 코드를 봅시다.
아래 코드는 한국 시간 기준 07-28 15:45분에 테스트 했을 경우 아래와 같이 22시가 나오는 것을 볼 수 있습니다.
var component = Calendar.current.dateComponents([.year, .month, .day], from: Date())
let dateWithoutTime = Calendar.current.date(from: component)!
let nextDate = Calendar.current.date(byAdding: .day, value: 1, to: dateWithoutTime)
print(nextDate) // 2024-07-28 22:00:00 +0000
뭔가 TimeZone이 잘 안 맞는 것 같죠?
한국으로 TimeZone을 설정해보겠습니다.
var component = Calendar.current.dateComponents([.year, .month, .day], from: Date())
component.timeZone = TimeZone(abbreviation: "KST")
let dateWithoutTime = Calendar.current.date(from: component)!
let nextDate = Calendar.current.date(byAdding: .day, value: 1, to: dateWithoutTime)
print(nextDate) // 2024-07-28 15:00:00 +0000
어라? 근데 28일 15시로 나오네요?
제가 기대했던 결과는 29일 00시 인데 말이죠.
여기서 다시 한번 봅시다. 결국 우리는 아래 로직을 체크하고 싶은건데요.
let isOver = Date() >= startOfNextDay
// 28일 15시 >= 28일 15시
// true
Date()는 UTC 기준이라고 했죠?
그럼 한국시간 기준 29일 00시에 Date를 찍는다면 28일 15시가 나올겁니다.
네 맞습니다. 그래서 위에서 나온 결과가 28일 15시인 것입니다.
그래야 정확한 비교가 되니까요?
만약 UTC 기준으로 Timezone을 설정하면 어떻게 될까요?
var component = Calendar.current.dateComponents([.year, .month, .day], from: Date())
component.timeZone = TimeZone(abbreviation: "UTC")
let dateWithoutTime = Calendar.current.date(from: component)!
let nextDate = Calendar.current.date(byAdding: .day, value: 1, to: dateWithoutTime)
print(nextDate) // 2024-07-29 00:00:00 +0000
UTC는 표준이기 때문에 29일 00시로 나옵니다.
하지만 한국시간 기준 29일 1시에 Date를 찍는다면 Date는 28일 16시로 나오기 때문에 우리가 원하던 동작을 하지 않을 것입니다.
let isOver = Date() >= startOfNextDay
// 28일 16시 >= 29일 00시
// false
그렇기 때문에 이런 경우 한국 시간을 timezone으로 잡고 비교해야합니다.
정리
1. Date()는 UTC 기준으로 한국 시간 보다 9시간 전의 값을 반환한다.
2. Date()로 비교하는 로직을 수행할때는 9시간 전 값이라는 것을 염두해두고 로직을 작성하자
3. formatter를 사용할때는 필요시 KST로 Timezone을 설정하자.