UTC 시간과 파이썬 : 기초UTC Time and Python: The Basics

UTC 시간의 개념과 파이썬에서 기본적인 UTC 시간 다루기What UTC is and the basics of working with UTC time in Python

written by tiaz0128

GMT, UTC 란

GMT (Greenwich Mean Time) 는 영국 런던의 그리니치 천문대에서 태양 위치를 측정하여 만든 표준시간 입니다.

UTC (Coordinated Universal Time) 는 GMT에 기반을 두고 있으나, 정밀한 원자시계를 사용하여 보다 정확하게 조정된 시간입니다. 1972 년 1월 1일부터 시행된 국제 표준시이며, 1970년 1월 1일 자정을 0 밀리 초를 기준 삼아 시간의 흐름을 밀리 초로 누적 계산합니다. 이러한 누적시간을 타임스탬프(TimeStamp) 라고 합니다.

UTC는 컴퓨터 시스템과 네트워킹에서 데이터 기록, 로그 관리, 시간 동기화 등에 중요하게 사용됩니다. 아래와 같이 여러가지 프로그래밍 언어에서 간단한 코드를 통해 UTC가 사용되고 있음을 확인 할 수 있습니다.

js
const Jan01_1970 = new Date(0);
Jan01_1970.valueOf() // 0

const now = new Date();
now.valueOf()        // 170........ 1970-01-01 이후 누적 밀리 초
python
from datetime import datetime

now = datetime.now()
print(now.timestamp()) # 170........ 1970-01-01 이후 누적 밀리 초

ISO 8601

그렇다면 UTC는 어떻게 표기 해야 할까요? 날짜, 시간, 그리고 시간대를 명확하고 일관된 형식으로 표현하기 위해 ISO 8601 표준을 따르면 됩니다. UTC 시간은 ISO 8601 표준에 따라 아래와 같이 표기될 수 있습니다.

2023-12-24T15:00:00Z

2023-12-24T15:00:00+00:00
  • 여기서 중간에 T는 날짜와 시간을 구분하는 구분자입니다.
  • 끝에 Z는 Zero time zone 즉, UTC를 의미합니다.
  • Z 는 시간대 오프셋으로 표현하면 +00:00 으로 표현할 수 있습니다.

시간대 오프셋

많은 국가와 지역은 고유의 표준 시간대를 가지고 있으며, 이는 UTC 오프셋으로 정의됩니다. 예를 들어, 한국 표준시(KST)는 UTC+9, 뉴욕(동부 표준시, EST)는 UTC-5입니다.

그림 1. UTC Map

지역 시간은 UTC 시간에 해당 지역의 오프셋을 더하거나 빼서 계산합니다. 예를 들어, UTC 시간이 0인 (= UTC) 영국이 크리스마스 이브 = 2023-12-24 일 15:00 시 이면, 시간대 오프셋이 +09:00인 한국은 크리스마스 당일 = 2023-12-25 일 0시 입니다.

2023-12-24T15:00:00Z

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

파이썬에서 UTC

Python에서 UTC 시간을 다루기 위한 datetime 모듈 주요 함수들은 다음과 같습니다.

  • datetime.now()
  • datetime.utcnow()
  • pytz 라이브러리

datetime.now()

현재 시스템의 로컬 시스템 시간을 반환합니다. 기본 호출(인수 없이)은 시간대 정보가 없는 naive datetime 객체를 반환합니다. 즉, datetime.now()로 생성된 datetime 객체는 시간대를 알 수 없습니다. UTC가 있는 구체적인 시간대와 비교하거나 변환하는 것이 명시적으로는 불가능합니다. 시간대 정보는 tzinfo 속성으로 확인 가능합니다.

python
from datetime import datetime

now = datetime.now()

print(now)        # 2023-12-25 00:00:00.000000
print(now.tzinfo) # None

datetime.utcnow()

이 함수는 현재 UTC 시간을 반환합니다. 하지만 이 함수도 시간대 정보가 없는 naive datetime 객체를 반환합니다. 즉, 제대로 된 UTC 활용이 어렵습니다. 그리고 python 3.12 버전 부터는 deprecated 되었기 때문에 사용하지 않는 것을 권장 합니다.

python
from datetime import datetime, UTC

utc_now = datetime.utcnow()

print(utc_now)        # 2023-12-24 15:00:00.000000
print(utc_now.tzinfo) # None

어웨어와 나이브 객체

날짜와 시간 객체는 시간대 정보를 포함하는지에 따라 어웨어(aware)와 나이브(naive)로 분류될 수 있습니다.

어웨어(aware)

어웨어 객체는 다른 어웨어 객체와의 상대적인 위치를 파악할 수 있습니다. 이는 일광 절약 시간(=DST), 썸머 타임 적용 또한 가능하게 합니다. 즉, 명확한 시간의 사용 및 계산이 가능합니다.

나이브(naive)

나이브 객체는 다른 시간과 상대적인 위치를 파악할 충분한 정보를 포함하지 않습니다. 나이브 객체가 UTC, 지역 시간 또는 다른 시간대의 시간 중 어느 것을 나타내는지는 순전히 프로그램에 달려있습니다. 나이브 객체는 이해하기 쉽고 작업하기 쉽지만, 시간을 다루는 로직에서 문제가 생길 수 있습니다.

timezone 추가하기

그렇다면 UTC 오프셋이 올바르게 적용된 시간 객체를 만드는 방법은 무엇일까요? timezone 이라는 오프셋을 의미하는 객체를 시간을 생성 할때 추가해주면 됩니다. UTC 0 을 의미하는 timezone.utc 또는 python 3.12 버전에서는 UTC 라는 별도의 상수값이 추가되어 이를 사용해도 됩니다.

python
from datetime import datetime, timezone, UTC

now = datetime.now(timezone.utc)

print(now)        # 2023-12-24 15:00:00.000000+00:00
print(now.tzinfo) # UTC

+09:00 한국 오프셋 설정

UTC+00:00 이외의 시간대를 표시 할 때는 오프셋 시간 만큼 timedelta 객체를 사용하여, timezone 객체를 직접 생성해서 사용하면 됩니다. +09:00 끝에 시간대 오프셋이 추가되어 출력되는 것을 확인 할 수 있습니다. 또한 tzinfo 속성값이 설정 된것을 확인 가능합니다.

python
from datetime import datetime, timezone, timedelta

tz = timezone(timedelta(hours=9))
now = datetime.now(tz)

print(now)        # 2023-12-25 00:00:00.000000+09:00
print(now.tzinfo) # UTC+09:00

pytz 라이브러리

여러나라의 timezone 을 하나씩 직접 시간 오프셋을 이용해서 만든다고 생각해봅시다. 어떤 나라의 어떤 도시는 어떤 오프셋을 가지는지 일일히 알아야 합니다. 이때 약 500 개 이상의 UTC 정보를 제공해주는 pytz 라이브러리를 사용하면 UTC를 포함한 다양한 시간대를 쉽게 다룰 수 있습니다.

$ pip install pytz
python
from datetime import datetime
from pytz import timezone, all_timezones

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

print(now)           # 2023-12-25 00:00:00.000000+09:00
print(now.tzinfo)    # Asia/Tokyo
print(all_timezones) # 지원하는 시간대 문자열 확인 가능

마무리

UTC는 시간을 국제 표준시이며, 많은 시스템과 프로그래밍에서도 이를 사용하고 활용하고 있습니다. UTC를 정확하게 표기 하기 위해서는 ISO 8601 를 따르면 됩니다. 하지만 위에서 출력된 결과는 어떤가요? 위에서 봤던 코드에는 함정이 있습니다. 다시 한번 잘 보시길 바랍니다.

과연? ISO 표준을 잘 준수해서 표현되고 있는지…

# 코드에서 만든 시간
2023-12-24 15:00:00.000000+00:00
2023-12-25 00:00:00.000000+09:00

# ISO 표준
2023-12-24T15:00:00.000000+00:00
2023-12-25T00:00:00.000000+09:00

날짜와 시간 사이에 구분 문자열인 T 가 빠져있는 것을 확인 할 수 있습니다. 이렇듯 표준과 다른 사소한 표기가 가져오는 몇 가지 문제가 있습니다. 🥲

다음으로

다음글에서 계속 됩니다.

실제 업무에서 구현하면서 만났던 문제는 UTC 시간과 파이썬 : 주의사항에서 알아보겠습니다.

  1. 날짜와 시간 구분자
  2. 시간대 표현법
  3. 시간대 오프셋을 고려해서 계산

What are GMT and UTC?

GMT (Greenwich Mean Time) is the standard time derived from measuring the position of the sun at the Royal Observatory in Greenwich, London.

UTC (Coordinated Universal Time) is based on GMT, but it is adjusted much more precisely using atomic clocks. It has been the international time standard since January 1, 1972, and it counts elapsed time in milliseconds, taking midnight on January 1, 1970 as 0 ms. This accumulated time is called a timestamp.

UTC plays a key role in computer systems and networking for things like recording data, managing logs, and synchronizing clocks. As the snippets below show, you can see UTC at work in many programming languages with just a few lines of code.

js
const Jan01_1970 = new Date(0);
Jan01_1970.valueOf() // 0

const now = new Date();
now.valueOf()        // 170........ milliseconds elapsed since 1970-01-01
python
from datetime import datetime

now = datetime.now()
print(now.timestamp()) # 170........ milliseconds elapsed since 1970-01-01

ISO 8601

So how should UTC be written? To express dates, times, and time zones in a clear, consistent format, you follow the ISO 8601 standard. Under ISO 8601, a UTC time can be written like this:

2023-12-24T15:00:00Z

2023-12-24T15:00:00+00:00
  • The T in the middle is the separator between the date and the time.
  • The Z at the end stands for the Zero time zone, i.e. UTC.
  • Expressed as a time zone offset, Z is +00:00.

Time zone offsets

Many countries and regions have their own standard time zone, defined as an offset from UTC. For example, Korea Standard Time (KST) is UTC+9, and New York (Eastern Standard Time, EST) is UTC-5.

Figure 1. UTC Map

Local time is calculated by adding or subtracting the region’s offset from UTC. For example, when it is Christmas Eve in the UK (offset 0, i.e. UTC) = 2023-12-24 at 15:00, it is Christmas Day in Korea (offset +09:00) = 2023-12-25 at 00:00.

2023-12-24T15:00:00Z

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

UTC in Python

These are the main datetime module functions for working with UTC time in Python:

  • datetime.now()
  • datetime.utcnow()
  • the pytz library

datetime.now()

Returns the current local system time. Called with no arguments, it returns a naive datetime object with no time zone information. In other words, a datetime created with datetime.now() doesn’t know its time zone, so you can’t explicitly compare it with or convert it to a concrete time zone such as UTC. You can check the time zone information through the tzinfo attribute.

python
from datetime import datetime

now = datetime.now()

print(now)        # 2023-12-25 00:00:00.000000
print(now.tzinfo) # None

datetime.utcnow()

This function returns the current UTC time. However, it also returns a naive datetime object with no time zone information, which makes it hard to use UTC properly. On top of that, it has been deprecated since Python 3.12, so I recommend not using it.

python
from datetime import datetime, UTC

utc_now = datetime.utcnow()

print(utc_now)        # 2023-12-24 15:00:00.000000
print(utc_now.tzinfo) # None

Aware and naive objects

Date and time objects can be classified as aware or naive, depending on whether they include time zone information.

Aware

An aware object can locate itself relative to other aware objects. This also makes it possible to apply daylight saving time (DST, a.k.a. summer time). In short, it lets you use and calculate time unambiguously.

Naive

A naive object doesn’t carry enough information to locate itself relative to other times. Whether a naive object represents UTC, local time, or some other time zone is entirely up to the program. Naive objects are easy to understand and easy to work with, but they can cause problems in time-handling logic.

Adding a timezone

So how do you create a time object with the correct UTC offset applied? Just pass a timezone object, which represents an offset, when you create the time. You can use timezone.utc, which means UTC 0, or, in Python 3.12, the newly added UTC constant.

python
from datetime import datetime, timezone, UTC

now = datetime.now(timezone.utc)

print(now)        # 2023-12-24 15:00:00.000000+00:00
print(now.tzinfo) # UTC

Setting the +09:00 Korean offset

For time zones other than UTC+00:00, create a timezone object yourself using a timedelta object for the offset. You can see that the output now ends with the +09:00 time zone offset, and that the tzinfo attribute is set.

python
from datetime import datetime, timezone, timedelta

tz = timezone(timedelta(hours=9))
now = datetime.now(tz)

print(now)        # 2023-12-25 00:00:00.000000+09:00
print(now.tzinfo) # UTC+09:00

The pytz library

Imagine building a timezone for every country by hand from its offset. You would have to know which offset each city in each country uses. Instead, use the pytz library, which provides information on more than 500 time zones, and you can easily work with many time zones, including UTC.

$ pip install pytz
python
from datetime import datetime
from pytz import timezone, all_timezones

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

print(now)           # 2023-12-25 00:00:00.000000+09:00
print(now.tzinfo)    # Asia/Tokyo
print(all_timezones) # lists the supported time zone strings

Wrapping up

UTC is the international time standard, and many systems and programs use it. To write UTC correctly, follow ISO 8601. But take another look at the output above. The code we’ve seen has a catch. Look closely one more time.

Really? Is it actually following the ISO standard…

# Times produced by the code
2023-12-24 15:00:00.000000+00:00
2023-12-25 00:00:00.000000+09:00

# ISO standard
2023-12-24T15:00:00.000000+00:00
2023-12-25T00:00:00.000000+09:00

You can see that the T separator between the date and the time is missing. Small deviations from the standard like this can lead to a few problems. 🥲

What’s next

Continued in the next post.

In UTC Time and Python: Pitfalls, we’ll look at the problems I actually ran into while implementing this at work.

  1. The date-time separator
  2. How time zones are expressed
  3. Calculating with time zone offsets in mind
python UTC

tiaz0128

Eat Sleep Coding.

Never Never GiveUp.

Security  |  BackEnd  |  Multi Cloud