문제상황
파이썬으로 코딩을 하다 보면, 타임존에 맞추어 날짜 계산을 해야 하는 경우가 더러 있다.
아래의 코드를 참고하자.
import pytz
from datetime import datetime
def main():
korea_tz = pytz.timezone('Asia/Seoul')
now_time = datetime.now(tz=korea_tz)
previous_time = datetime.strptime('2023-07-01T20:32:21Z', "%Y-%m-%dT%H:%M:%SZ")
print(now_time - previous_time)
"""
main function - execute
"""
if __name__ == '__main__':
main()
위의 코드는 timezone 이 한국인 현재 시각을 now_time 변수로 초기화하고 있다.
previous_time 은 직접 날짜를 입력하여 string 타입의 날짜 데이터를 datetime 객체로 바꾸어주고 있다.
해당 소스를 실행시키면 아래와 같은 오류가 발생한다.
문제분석
TypeError: can't subtract offset-naive and offset-aware datetimes 에러가 발생하고 있다.
오류가 발생하는 이유는 previous_time 변수가 "offset-naive" datetime 객체이고,
now_time 변수가 "offset-aware" datetime 객체이기 때문이다.
"offset-naive" datetime 객체는 타임존 정보를 가지고 있지 않으며, 시간대 변환을 할 수 없다.
반면에 "offset-aware" datetime 객체는 타임존 정보를 가지고 있어 시간대 변환이 가능하다.
offset-naive 란?
Offset-naive 객체는 시간대(TZ, Time Zone) 정보를 포함하지 않는 datetime 객체를 의미한다.
즉, 시간대에 대한 정보가 없으며, 일반적으로 지역 시간을 나타낸다.
이러한 객체는 시간대 변환을 수행할 수 없으며,
일반적으로 로컬 타임 존 또는 UTC(협정 세계시)를 기준으로 시간을 표시한다.
예를 들어, "2023-08-07 12:34:56"과 같은 datetime 객체는 시간대 정보가 없으며,
이를 "offset-naive" 객체라고 한다.
이 객체를 사용하면 시간대 변환이나 서로 다른 시간대의 날짜 및 시간 비교가 어렵다.
offset-aware 란?
Offset-aware 객체는 시간대 정보를 포함하는 datetime 객체를 의미한다.
이러한 객체는 특정 시간대를 나타내며, 시간대 변환을 수행할 수 있다.
시간대 변환이 가능하므로 서로 다른 시간대의 날짜와 시간을 변환하거나 비교하는 것이 쉽다.
예를 들어, "2023-08-07 12:34:56+09:00"과 같은 datetime 객체는 시간대 정보(+09:00)를 포함하고 있으며,
이를 "offset-aware" 객체라고 한다.
이 객체를 사용하면 해당 시간대에서 다른 시간대로 변환하거나,
서로 다른 시간대의 시간을 비교하는 등 시간대 관련 작업을 수행할 수 있다.
문제해결 방법
1. offset-naive 객체의 timezone 을 지정하는 방법
offset-naive 는 시간대 정보를 포함하지 않으므로,
해당 offset-naive 객체를 offset-aware 객체로 변환한 뒤 두 시각을 빼주면 된다.
import pytz
from datetime import datetime
def main():
korea_tz = pytz.timezone('Asia/Seoul')
now_time = datetime.now(tz=korea_tz)
previous_time = datetime.strptime('2023-07-01T20:32:21Z', "%Y-%m-%dT%H:%M:%SZ")
# 기존 offset-naive 인 previous_time 객체를 offset-aware 객체로 변환
previous_time_aware = korea_tz.localize(previous_time)
print(now_time - previous_time_aware)
"""
main function - execute
"""
if __name__ == '__main__':
main()
2. offset-aware 객체를 offset-naive 객체로 바꾸는 방법
두 번째 방법은 시간대 정보를 포함하고 있는 offset-aware 객체에서 시간대 정보를 제외시켜
offset-naive 객체로 바꿔버리는 것이다.
import pytz
from datetime import datetime
def main():
korea_tz = pytz.timezone('Asia/Seoul')
now_time = datetime.now(tz=korea_tz)
# 기존 offset-aware인 previous_time 객체를 offset-naive 객체로 변환
naive_now_time = now_time.replace(tzinfo=None)
previous_time = datetime.strptime('2023-07-01T20:32:21Z', "%Y-%m-%dT%H:%M:%SZ")
print(naive_now_time - previous_time)
"""
main function - execute
"""
if __name__ == '__main__':
main()
이렇게 하면 offset-naive 객체와 offset-naive 객체를 비교하게 되므로,
에러가 발생하지 않게 된다.