UTC 시간과 파이썬 : 유의사항

datetime 출력 결과 확인


앞서 본 문자열을 다시 한번 확인 해보겠습니다. 앞서 코드로 timezone 까지 입력하면서 제대로 UTC 포맷을 지켰다고 생각 할 수 있습니다. 하지만 실제 출력결과는 ISO 표준과 차이가 있습니다.

ISO 포맷을 지키는 것은 매우 중요합니다. 일반적인 웹 프론트-백 연동 뿐 아니라, 다른 서비스와 데이터를 주고 받는 통신에서 표준을 지키지 않는다면 서로 다른 시간값을 의미 할 수 있습니다.

# 코드에서 만든 시간 문자열
2023-12-24 15:00:00.000000+00:00

2023-12-25 00:00:00.000000+09:00

ISO 표준 다시 확인


다시 한번 ISO 표준 표기법에 대해서 상기해 보겠습니다. 크게 두 가지를 기억해야 합니다.

2023-12-24T15:00:00Z

2023-12-24T15:00:00+00:00

실제 표준 문자열과 비교해보면, 코드 결과에서는 구분자 T 가 빠진 것을 확인 할 수 있습니다. 그럼 어떻게 해야 datetime 객체를 ISO 표준 문자열로 표현 할 수 있는 지 알아 봅시다.

  1. strftime() : 포맷 문자열 사용하여 변환
  2. isoformat() : ISO 표준 문자열로 변환

strftime() : datetime 객체 → 문자열


가장 기본적인 방법으로는 strftime 함수를 사용하는 방법입니다. 정해진 포맷 문자열을 사용하여 datetime 객체를 문자열로 변환 할 수 있습니다. 아래와 같이 ISO 포맷에 알맞은 문자열을 구성하여 표준을 지키는 문자열과 사용자가 원하는 형태의 문자열로 만들 수 있습니다.

python
from datetime import datetime, timezone

utc_time = datetime.now(timezone.utc)
custom_str_time = utc_time.strftime("%Y/%m/%d")         # 커스텀 시간 문자열
iso_str_time = utc_time.strftime("%Y-%m-%dT%H:%M:%SZ")  # ISO 표준을 따른 포맷

print(utc_time)        # 2023-12-24 15:00+00:00
print(custom_str_time) # 2023-12-24
print(iso_str_time)    # 2023-12-24T15:00+00:00

시간 포맷 문자열

아래의 기본적인 포맷 이외에도 많은 포맷이 있습니다. 🔗공식 문서를 참고 하시길 바랍니다.

포맷 의미
%Y 연도 (네 자리 숫자)
%m 월 (두 자리 숫자)
%d 일 (두 자리 숫자)
%H 시간을 24시간 형식으로 (두 자리 숫자)
%M 분 (두 자리 숫자)
%S 초 (두 자리 숫자)
%f 마이크로초를 (숫자)

시간대 표현 문제점


strftime 를 사용해도 제대로 잘 작동하는것 같습니다. 하지만 여기서 문제는 여러 시간대를 표현해야 하는 경우 입니다. 이 경우는 각 시간대에 알맞은 시간대 문자열을 각각 직접 지정해줘야 합니다.

아래의 예제 같은 경우 UTC 가 아닌 시간대를 UTC 로 표기하게 되면서 9시간이라 시차가 발생하게 됐습니다.

python
from datetime import datetime
from pytz import timezone

tz = timezone("Asia/Seoul")
now = datetime.now(tz)
iso_str_time = now.strftime("%Y-%m-%dT%H:%M:%SZ")  # UTC - ISO 표준을 따른 포맷

print(iso_str_time) # 2023-12-25T00:00+00:00 = 잘못된 UTC 값으로 표현

isoformat() : ISO 표기에 따른 변환


위에서 사용한 strftime 함수에서는 사용자가 직접 ISO 표준에 맞는 문자열을 구성해야 했습니다. 뿐만 아니라 시간대에 따라서 각각의 문자열을 지정해야 하는 문제가 있습니다.

이를 간단하게 isoformat 함수를 사용해서 일일히 작성 할 필요없이 표준을 준수하는 문자열을 만들 수 있습니다.

python
from datetime import datetime
from pytz import timezone

tz = timezone("Asia/Seoul")
now = datetime.now(tz)

iso_str_time = now.isoformat()
iso_seconds_time = now.isoformat(sep="T", timespec="seconds")

print(now)               # 2023-12-25 00:00:00.0000+09:00
print(iso_str_time)      # 2023-12-25T00:00:00.000000+09:00 = 알맞은 시간대까지 표현
print(iso_seconds_time)  # 2023-12-25T00:00:00+09:00 = 밀리초는 제거된것 확인

isoformat 함수 호출 시, 선택적으로 두 가지 인자값을 넣어 줄 수 있습니다.

구분자 기능
sep 날짜와 시간 사이의 구분자를 지정하는데, 기본값은 ‘T’입니다.
timespec 시간 중 어디까지 포함해서 문자열을 구성 할 것인지, 시간 단위를 지정합니다.
유효한 옵션은 ‘auto’, ‘hours’, ‘minutes’, ‘seconds’, ‘milliseconds’, ‘microseconds’입니다.

문자열에서 변환


이제까지는 datetime 객체에서 문자열로 변환하는 것을 알아보았습니다.

이번에는 문자열에서 datetime 객체를 만드는 방법에 대해서 알아보겠습니다.

  1. strptime() : 지정한 포맷을 따르는 문자열에서 변환
  2. fromisoformat() : ISO 표준 문자열에서 변환

strptime() : 문자열 → datetime 객체


가장 기본적인 문자열에서 시간을 만들 때 쓰는 함수입니다. 먼저 문자열로 들어오는 시가 형식에 알맞은 포맷 문자열을 만들어 줍니다. 해당하는 포맷에 알맞지 않는 경우, ValueError 예외가 발생합니다.

이 함수도 시간대에 따른 시간대를 표기 해줘야 하는 문제가 존재합니다. 서울 시간대를 예를 들면 정확히 +09:00 라는 문자열을 포맷에 지정 해줘야 에러가 발생하지 않습니다.

python
from datetime import datetime

date_string = "2023-12-25T00:00:00+09:00"
date_format = "%Y-%m-%dT%H:%M:%S+09:00"

# datetime 객체로 변환
datetime_obj = datetime.strptime(date_string, date_format)

fromisoformat() : ISO 포맷 문자열 → datetime 객체


문자열이 ISO 포맷에 일치하는 경우 시간대를 알아서 반영해서 datetime 객체를 생성해줍니다. 시간 구분자가 T가 아니라 공백으로 되어있거나 다른 문자로 되어있더라도 해당 형식에 맞게 파싱을 시도합니다. 공백 하나, T 가 아닌 다른 문자 하나인 경우는 자동으로 처리 합니다. 다만, 이외의 형식과 다르다면 파싱에 실패할 수 있습니다.

python
from datetime import datetime

date_string = "2023-12-25 00:00:00+09:00"
date_format = "%Y-%m-%dT%H:%M:%S+09:00"

# datetime 객체로 변환
datetime_obj = datetime.fromisoformat(date_string)
print(datetime_obj.tzinfo) # UTC+09:00

다른 시간대로 변환


이번에는 UTC 를 다른 시간대로 변환하거나 다른 시간대를 UTC 로 변환하는 방법에 대해서 알아 보겠습니다.

  1. timedelta 객체로 계산하기
  2. astimezone() : 서로 다른 시간대로 변경

아래와 같이 UTC 시간을 한국 시간인 UTC+9 인 시간대로 변환한다고 가정하겠습니다. (밀리초는 무시하고 설명 하겠습니다.)

2023-12-24T15:00:00Z

2023-12-25T00:00:00+09:00

datedelta 객체 이용


UTC 시간에서 한국 시간대는 9시간이 빠르므로 9시간을 더해주면 간단하게 시간을 계산 할 수 있습니다. 이때 시간 계산에는 datedelta 객체를 이용하여 9 시간을 더 해줍니다.

하지만 더하고 결과를 확인해보면 문제가 있습니다. 시간대가 그대로 UTC 를 의미하는 +00:00 인 상태 그대로 입니다. 의도와 달리 본래 UTC 시간보다 9시간 더 빠른 UTC 시간을 의미하게 됐습니다.

python
from datetime import datetime, timezone, timedelta

utc_time = datetime.now(timezone.utc)
kor_time = utc_time + timedelta(hours=9)

print(utc_time) # 2023-12-24 15:00:00+00:00
print(kor_time) # 2023-12-25 00:00:00+00:00
print(kor_time.tzinfo) # UTC

astimezone() : UTC ↔ 다른 시간대


astimezone 함수를 서로 다른 시간대를 간단하게 변경 할 수 있습니다. 시간대 정보까지 고려해서 다른 시간대로 변경해줍니다.

변환하고자 하는 목표 시간대를 정확히 지정해야 합니다. 예를 들어, ‘EST’나 ‘CST’와 같은 약어 대신 ‘America/New_York’, ‘Asia/Seoul’ 등의 정확한 시간대 이름을 사용하는 것이 좋습니다. pytz 라이브러리를 사용해서 정확한 시간대를 설정합니다.

python
from datetime import datetime, UTC
from pytz import timezone

utc_time = datetime.now(UTC)
target_timezone = timezone("Asia/Seoul")

kor_time = utc_time.astimezone(target_timezone)

print(utc_time)        # 2023-12-24 15:00:00+00:00
print(kor_time)        # 2023-12-25 00:00:00+09:00
print(kor_time.tzinfo) # Asia/Seoul

마치면서


UTC 시간을 사용하여 데이터 통신을 하는 경우 반드시 표준을 준수하는 형태의 시간대 문자열을 사용 해야 혼동이 없습니다. 또한 시간을 계산할 때는 해당하는 시간의 시간대를 확인하고 그에 따른 알맞은 함수를 써서 시간대에 따른 오차가 없도록 해야 합니다.

  1. strftime() 보다는 isoformat() 를 사용
  2. timedelta 객체로 직접 계산보다 astimezone() 를 사용

이상으로 UTC 를 파이썬에서 다루는 기본적인 내용을 알아보았습니다. 감사합니다. 😊

python UTC