파이썬 날짜시간 모듈(datetime) 치트시트

개요

프로그램을 작성하다 의외로 시간 정보가 중요하게 작용할 때가 많습니다. 특히 글로벌 서비스를 만들다보면, 하나의 통일된 시간을 사용해야 하는 경우가 많죠.

예를 들어, 메신저나 게시판을 만들 때 이 글이 몇 분 전 혹은 몇 시간 전에 작성된 글인지 표시를 하려고만 하더라도 통일된 시간 혹은 그에 준하는 시간을 데이터로 가지고 있어야합니다.

이럴 때 사용할 수 있는 가장 좋은 방법 중 하나는 표준 시간대(Timezone) 정보를 추가하는 것 입니다. 이 글에서는 파이썬에서 표준 시간대를 사용할 때 주의할 점에 대해 정리해보고자 합니다.

치트시트

파이썬의 datetime은 표준 시간대의 세팅 여부에 따라 다음 두 가지로 나눠집니다.

중요: Naive Datetime과 Aware Datetime은 서로 대소 비교 및 연산이 불가능. 반드시 어느 한 쪽으로 맞춰줘야 합니다.

명령어 별 결과

TZ = Asis/Seoul 을 기준으로 계산할 때.

>>> datetime(2019, 1, 1)
datetime.datetime(2019, 1, 1, 0, 0)

# 2019년 1월 1일 0시. TZ = None
>>> datetime(2019, 1, 1, tzinfo=timezone.utc)
datetime.datetime(2019, 1, 1, 0, 0, tzinfo=timezone.utc)

# 2019년 1월 1일 0시. TC = UTC
>>> datetime.fromtimestamp(1546268400.0)
datetime.datetime(2019, 1, 1, 0, 0)

# 2019년 1월 1일 0시. TZ = None
>>> datetime.fromtimestamp(1546268400.0, tzinfo=timezone.utc)
datetime.datetime(2018, 12, 31, 15, 0, tzinfo=timezone.utc)

# 2018년 12월 31일 15시. TZ = UTC
>>> datetime(2019, 1, 1).replace(tzinfo=timezone.utc)
datetime.datetime(2019, 1, 1, 0, 0, tzinfo=timezone.utc)

# 2019년 1월 1일 0시. TZ = UTC
>>> datetime(2019, 1, 1).astimezone(timezone.utc)
datetime.datetime(2018, 12, 31, 15, 0, tzinfo=timezone.utc)

2018년 12월 31일 15시. TZ = UTC
>>> datetime.now()
datetime.datetime(2019, 1, 1, 0, 0)

# 로컬 현 시간. TZ = None.
>>> datetime.now(tz=timezone.utc)
datetime.datetime(2018, 12, 31, 15, 0, tzinfo=timezone.utc)

# datetime.now().astimezone(timezone.utc)와 동일.
>>> datetime.utcnow()
datetime.datetime(2018, 12, 31, 15, 0)

# UTC 기준 현 시간. TZ = None. (한국 기준에서는 과거 시간이 나옴.)

치트시트 분석

이제 위의 명령어들이 왜 저렇게 동작하는지 분석해 봅시다. 이해를 돕기위해 중요한 용어에 대해서는 아래에 따로 정리해 두었습니다.

위의 명령어들을 살펴보면 datetime은 기본적으로 tzinfo(표준 시간대 정보)를 세팅하지 않음을 알 수 있습니다. 아마도 표준 시간대를 고려하지 않았던 시절에 작성한 코드와의 호환성을 유지하기 위함으로 추정됩니다.

datetime(year, month, day) vs datetime(year, month, day, tzinfo=tz)

datetime(2019, 1, 1)은 Naive Datetime 2019년 1월 1일이 됩니다. 물론 datetime(2019, 1, 1, tzinfo=timezone.utc)와 같이 명령어에서 명시적으로 tzinfo를 지정하는 경우에는 표준 시간대를 지정합니다. 이 경우 UTC+0을 지역시로 하는 Aware Datetime 2019년 1월 1일 0시의 시간이 됩니다.

여기까지는 딱히 어려울 게 없습니다.

datetime.fromtimestamp(ts) vs datetime.fromtimestamp(ts, tzinfo=tz)

datetime.fromtimestamp(1546268400.0)이 명령의 결과는 좀 특이합니다. 유닉스 시간이 UTC를 기본으로 함에도 불구하고 이 명령어는 표준 시간대를 지정하지 않습니다. 두 번째 명령어와 비교해보면, 첫 번째 명령어는 tzinfo값이 None일 뿐만 아니라 표준 시간대를 지역시(이 경우, Asia/Seoul)로 계산했음을 알 수 있습니다. 분명 호환성을 유지하기 위함이겠지만, 개인적으로 직관과 대치되서 힘들었던 부분입니다.

datetime().replace(tzinfo) vs datetime().astimezone()

replace는 tzinfo를 단순히 덮어쓰는 명령어이고, astimezone은 표준 시간대를 변경하면 지역시가 어떻게 바뀌는지 계산해줍니다.

replace는 각 시간대별 시차를 계산할 때 사용할 수 있고, astimezone은 다른 나라의 지역시를 계산할 때 사용할 수 있습니다.

용어 정리

타임스탬프 (Timestamp)

원래 타임스탬프는 편지나 문서의 발송 및 접수 날짜를 기록하는 것 입니다. 그래서 컴퓨터에서는 어떤 이벤트가 발생했을 때의 날짜와 시간에 대한 기록을 나타냅니다. 따라서 아래의 예시는 모두 타임스탬프에 해당합니다.

프로그래밍을 하다보면 보통 1575101062와 같이 숫자로만 표현된 것을 타임스탬프라 생각하곤 하는데 이는 시간을 표시할 때 유닉스 시간(Unix Time) 방식을 사용하기 때문입니다.

유닉스 시간(Unix Time)*

POSIX Time 혹은 Epoch Time이고도 부르는 이 시간 표기법은 1970-01-01 T 00:00:00 UTC를 기준으로 몇 초가 흘렀는지를 표기하는 방식입니다. 초 단위로 표시되는 일종의 세계 표준시라고 생각할 수 있습니다. 그래서 시간을 비교할 때에는 유닉스 시간에서 사용하는 타임스탬프를 이용하는 것이 가장 편한 방법입니다. 예를 들어, 2019-01-01 UTC+92018-12-31 UTC의 유닉스시간은 1546268400로 동일하기 때문에, 같은 시간임을 알 수 있습니다.

초 단위를 기본으로 하기 때문에 보통 Integer가 사용됩니다. 파이썬은 Integer대신 Float을 사용해서 마이크로초까지 표시하곤 합니다.

참고로 유닉스 시간은 2038년에 Integer범위를 벗어난다고 합니다.**

협정 세계시(UTC)*

정오(낮 12시)는 태양이 가장 높이 떠있는 지점을 의미합니다. 그래서 내가 어디에 있느냐에 따라 정오일 수도 있고 아닐 수도 있습니다. 이렇게 생각해보면 지구에서의 시간이란 그 지역에서 보이는 태양의 위치라 할 수도 있습니다. 달리 말해 지역에 따라 시간은 달라질 수 밖에 없다는 뜻이기도 합니다.

그렇다고 100미터 걸어갈 때마다 시간을 다시 기록할 수는 없는 노릇이기에 전 세계가 합의하에 협정 세계시라는 것을 정하게 되었습니다. 우선 경도가. 서경 7.5º ~ 동경 7.5º 사이의 구역을 기준시로 잡습니다. 이후 동서로 경도 15º 간격으로 구역을 나눠 전 세계를 총 24개의 구역으로 나눕니다. 그리고 각 구역은 인접한 구역과 1시간의 차이를 갖도록 정한게 협정 세계시입니다.

예를 들어, 동경 3º의 시간이 12시라고 한다면, 동경 15º의 시간은 13시가 됩니다. 그리고 동경 8º와 동경 15º는 서로 같은 구역이기 때문에, 동경 8º의 시간 역시 13시가 됩니다.

표준 시간대(Timezone)*

협정 세계시는 매우 합리적으로 보이지만, 국가 단위로 적용하기에는 다소 무리가 있습니다. 횡단보도 하나를 경계로 1시간의 차이가 발생할 수도 있기 때문이죠. 그래서 각 국가의 사정에 따라 자신들이 원하는 시간대를 선택할 수 있게 한 것이 표준 시간대 입니다. 한국은 협정 세계시를 기준으로 9시간 빠른 UTC+9:00를 한국 표준시로 사용하고 있습니다. 이렇게 정해진 지역시는 KST 혹은 Asia/Seoul이라고도 불립니다.

유용한 라이브러리

datetime은 사용법이 다소 직관적이지 않다보니 좀 더 고차원적인 라이브러리가 많이 만들어지고 있습니다. 그 중에서도 arrow, maya는 상당히 고차원 라이브러리로 시간으로 상상할 수 있는 거의 모든 것이 구현되어 있습니다. 한번 살펴보시면 많은 도움이 될 것입니다.