Skip to content

Python Datetime: Python 날짜와 시간 완전 가이드

Updated on

Python에서 날짜와 시간 작업은 간단해야 하지만, 실제로는 거의 그렇지 않습니다. CSV 파일에서 날짜 문자열을 파싱해야 하는데, "01/02/2026"은 로케일에 따라 1월 2일 또는 2월 1일을 의미할 수 있습니다. 두 타임스탬프의 차이를 계산하고 싶지만, 하나는 문자열이고 다른 하나는 Unix 에포크입니다. 이번 달에 벌써 열 번째로 strftimestrptime을 혼동합니다. 날짜와 시간 연산은 프로덕션 코드에서 버그, off-by-one 오류, 타임존 두통의 끊임없는 원인입니다.

그 결과는 단순한 불편함을 넘어섭니다. 재무 보고서의 잘못된 날짜 형식은 잘못된 계산을 의미합니다. 타임존을 무시하는 naive datetime 비교는 중복 cron 작업을 유발합니다. 잘못된 timedelta 계산은 고객에게 30일이 아닌 31일을 청구합니다.

Python의 내장 datetime 모듈은 깔끔하고 일관된 API로 이러한 문제를 해결합니다. 날짜, 시간, 타임스탬프, 기간을 위한 클래스를 제공합니다. 패턴을 배우면 -- 특히 strftimestrptime의 차이를 이해하면 -- 서드파티 라이브러리 없이 모든 날짜 연산을 처리할 수 있습니다.

📚

현재 날짜와 시간 가져오기

가장 일반적인 시작점은 현재 날짜와 시간을 가져오는 것입니다. datetime 모듈은 이를 위한 여러 가지 방법을 제공합니다.

from datetime import datetime, date
 
# 현재 날짜와 시간
now = datetime.now()
print(now)           # 2026-02-10 14:30:45.123456
 
# 현재 날짜만
today = date.today()
print(today)         # 2026-02-10
 
# datetime.today()는 datetime.now()와 비슷하지만 타임존 지원 없음
now_alt = datetime.today()
print(now_alt)       # 2026-02-10 14:30:45.123456

datetime.now()datetime.today()의 차이는 미묘하지만 중요합니다. datetime.now()는 타임존 인식 datetime을 위한 선택적 tz 매개변수를 받습니다. datetime.today()는 받지 않습니다. 대부분의 코드에서는 datetime.now()를 선호하세요.

from datetime import datetime
from zoneinfo import ZoneInfo
 
# 타임존 인식 현재 시간
utc_now = datetime.now(tz=ZoneInfo("UTC"))
print(utc_now)  # 2026-02-10 14:30:45.123456+00:00
 
tokyo_now = datetime.now(tz=ZoneInfo("Asia/Tokyo"))
print(tokyo_now)  # 2026-02-10 23:30:45.123456+09:00

Datetime 객체 생성

개별 구성 요소 또는 기존 데이터에서 datetime 객체를 생성할 수 있습니다.

from datetime import datetime, date, time
 
# 연, 월, 일, 시, 분, 초에서
dt = datetime(2026, 3, 15, 9, 30, 0)
print(dt)  # 2026-03-15 09:30:00
 
# 날짜만
d = date(2026, 12, 25)
print(d)  # 2026-12-25
 
# 시간만
t = time(14, 30, 0)
print(t)  # 14:30:00
 
# 날짜와 시간 결합
combined = datetime.combine(d, t)
print(combined)  # 2026-12-25 14:30:00

기존 datetime에서 구성 요소를 추출할 수도 있습니다.

from datetime import datetime
 
dt = datetime(2026, 3, 15, 9, 30, 45)
 
print(dt.year)        # 2026
print(dt.month)       # 3
print(dt.day)         # 15
print(dt.hour)        # 9
print(dt.minute)      # 30
print(dt.second)      # 45
print(dt.weekday())   # 6 (일요일, 월요일=0)
print(dt.isoformat()) # 2026-03-15T09:30:45

strftime으로 날짜 포맷팅

strftime은 "string format time"(문자열 포맷 시간)의 약자입니다. datetime 객체를 포맷된 문자열로 변환합니다. 날짜 구성 요소로 대체되는 지시자가 포함된 포맷 문자열을 전달합니다.

from datetime import datetime
 
dt = datetime(2026, 3, 15, 9, 5, 7)
 
# 일반적인 포맷
print(dt.strftime("%Y-%m-%d"))              # 2026-03-15
print(dt.strftime("%d/%m/%Y"))              # 15/03/2026
print(dt.strftime("%B %d, %Y"))             # March 15, 2026
print(dt.strftime("%Y-%m-%d %H:%M:%S"))     # 2026-03-15 09:05:07
print(dt.strftime("%I:%M %p"))              # 09:05 AM
print(dt.strftime("%A, %B %d, %Y"))         # Sunday, March 15, 2026

기억하는 방법: strftime = string from time (datetime에서 문자열로).

strftime 포맷 코드 참조

코드의미예시
%Y4자리 연도2026
%y2자리 연도26
%m0으로 채운 월03
%B월 전체 이름March
%b월 약어Mar
%d0으로 채운 일15
%A요일 전체 이름Sunday
%a요일 약어Sun
%H시간 (24시간, 0 채움)09
%I시간 (12시간, 0 채움)09
%M분 (0 채움)05
%S초 (0 채움)07
%pAM/PMAM
%f마이크로초 (6자리 0 채움)000000
%zUTC 오프셋 (+HHMM 또는 -HHMM)+0000
%Z타임존 이름UTC
%j연중 일수 (001-366)074
%%리터럴 % 문자%

가장 많이 사용되는 포맷 패턴

패턴포맷 문자열출력
ISO 8601%Y-%m-%dT%H:%M:%S2026-03-15T09:05:07
미국 날짜%m/%d/%Y03/15/2026
유럽 날짜%d/%m/%Y15/03/2026
읽기 쉬운 날짜%B %d, %YMarch 15, 2026
로그 타임스탬프%Y-%m-%d %H:%M:%S2026-03-15 09:05:07
12시간 시간%I:%M:%S %p09:05:07 AM
컴팩트 날짜%Y%m%d20260315
파일 안전 타임스탬프%Y%m%d_%H%M%S20260315_090507

strptime으로 문자열 파싱

strptime은 "string parse time"(문자열 파싱 시간)의 약자입니다. strftime의 반대로 -- 문자열을 datetime 객체로 변환합니다. 문자열과 해당 포맷을 제공합니다.

from datetime import datetime
 
# 다양한 날짜 문자열 포맷 파싱
dt1 = datetime.strptime("2026-03-15", "%Y-%m-%d")
print(dt1)  # 2026-03-15 00:00:00
 
dt2 = datetime.strptime("15/03/2026", "%d/%m/%Y")
print(dt2)  # 2026-03-15 00:00:00
 
dt3 = datetime.strptime("March 15, 2026 09:30 AM", "%B %d, %Y %I:%M %p")
print(dt3)  # 2026-03-15 09:30:00
 
dt4 = datetime.strptime("2026-03-15T09:30:00", "%Y-%m-%dT%H:%M:%S")
print(dt4)  # 2026-03-15 09:30:00

기억하세요: strptime = string parse time (문자열에서 datetime으로).

파싱 오류 처리

문자열이 포맷과 일치하지 않으면 Python은 ValueError를 발생시킵니다. 사용자 입력이나 외부 데이터를 파싱할 때는 항상 strptime 호출을 오류 처리로 감싸세요.

from datetime import datetime
 
def safe_parse_date(date_string, fmt="%Y-%m-%d"):
    """Parse a date string safely, returning None on failure."""
    try:
        return datetime.strptime(date_string, fmt)
    except ValueError as e:
        print(f"Could not parse '{date_string}': {e}")
        return None
 
# Valid input
print(safe_parse_date("2026-03-15"))       # 2026-03-15 00:00:00
 
# Invalid input
print(safe_parse_date("15-03-2026"))       # Could not parse '15-03-2026': ...
print(safe_parse_date("not a date"))       # Could not parse 'not a date': ...

여러 포맷 파싱

예측할 수 없는 포맷의 날짜를 받을 때는 여러 패턴을 시도합니다.

from datetime import datetime
 
def parse_flexible_date(date_string):
    """Try multiple date formats and return the first match."""
    formats = [
        "%Y-%m-%d",
        "%d/%m/%Y",
        "%m/%d/%Y",
        "%B %d, %Y",
        "%b %d, %Y",
        "%Y-%m-%dT%H:%M:%S",
        "%Y-%m-%d %H:%M:%S",
    ]
    for fmt in formats:
        try:
            return datetime.strptime(date_string, fmt)
        except ValueError:
            continue
    raise ValueError(f"No matching format found for '{date_string}'")
 
print(parse_flexible_date("2026-03-15"))         # 2026-03-15 00:00:00
print(parse_flexible_date("March 15, 2026"))     # 2026-03-15 00:00:00
print(parse_flexible_date("15/03/2026"))         # 2026-03-15 00:00:00

timedelta를 사용한 날짜 연산

timedelta 클래스는 기간 -- 두 날짜 또는 시간의 차이를 나타냅니다. timedelta 객체를 더하거나 빼서 날짜를 앞뒤로 이동할 수 있습니다.

from datetime import datetime, timedelta
 
now = datetime(2026, 2, 10, 12, 0, 0)
 
# 일수 더하기
tomorrow = now + timedelta(days=1)
print(tomorrow)  # 2026-02-11 12:00:00
 
# 일수 빼기
last_week = now - timedelta(weeks=1)
print(last_week)  # 2026-02-03 12:00:00
 
# 시간과 분 더하기
later = now + timedelta(hours=5, minutes=30)
print(later)  # 2026-02-10 17:30:00
 
# 여러 단위 결합
future = now + timedelta(weeks=2, days=3, hours=6)
print(future)  # 2026-02-27 18:00:00

시간 차이 계산

하나의 datetime에서 다른 datetime을 빼면 timedelta가 반환됩니다.

from datetime import datetime
 
start = datetime(2026, 1, 1)
end = datetime(2026, 12, 31)
 
diff = end - start
print(diff)              # 364 days, 0:00:00
print(diff.days)         # 364
print(diff.total_seconds())  # 31449600.0

timedelta 생성자 매개변수

매개변수설명예시
weeks주 수timedelta(weeks=2) = 14일
days일 수timedelta(days=30)
hours시간 수timedelta(hours=12)
minutes분 수timedelta(minutes=45)
seconds초 수timedelta(seconds=120)
milliseconds밀리초 수timedelta(milliseconds=500)
microseconds마이크로초 수timedelta(microseconds=1000)

모든 매개변수를 결합할 수 있습니다. 내부적으로 timedeltadays, seconds, microseconds만 저장합니다. 나머지는 모두 변환됩니다.

from datetime import timedelta
 
delta = timedelta(weeks=1, days=2, hours=3, minutes=30, seconds=45)
print(delta)                    # 9 days, 3:30:45
print(delta.days)               # 9
print(delta.seconds)            # 12645 (3*3600 + 30*60 + 45)
print(delta.total_seconds())    # 790245.0

날짜 비교

Datetime 객체는 모든 표준 비교 연산자를 지원합니다. 이를 통해 날짜 정렬과 필터링이 간단해집니다.

from datetime import datetime
 
dt1 = datetime(2026, 1, 1)
dt2 = datetime(2026, 6, 15)
dt3 = datetime(2026, 12, 31)
 
print(dt1 < dt2)    # True
print(dt3 > dt2)    # True
print(dt1 == dt2)   # False
print(dt1 != dt2)   # True

날짜 정렬

from datetime import datetime
 
dates = [
    datetime(2026, 12, 25),
    datetime(2026, 1, 1),
    datetime(2026, 7, 4),
    datetime(2026, 2, 14),
]
 
sorted_dates = sorted(dates)
for d in sorted_dates:
    print(d.strftime("%B %d, %Y"))
 
# January 01, 2026
# February 14, 2026
# July 04, 2026
# December 25, 2026

타임스탬프 작업

Unix 타임스탬프는 1970년 1월 1일(Unix 에포크) 이후의 초를 나타냅니다. datetime 모듈은 타임스탬프와 datetime 객체 간의 변환이 가능합니다.

from datetime import datetime, timezone
 
# Datetime에서 타임스탬프로
dt = datetime(2026, 3, 15, 9, 30, 0)
ts = dt.timestamp()
print(ts)  # 1773814200.0 (로컬 타임존에 따라 다름)
 
# 타임스탬프에서 Datetime으로 (타임존 인식, 권장)
dt_aware = datetime.fromtimestamp(ts, tz=timezone.utc)
print(dt_aware)  # 2026-03-15 01:30:00+00:00

중요: 타임존 없는 datetime.fromtimestamp()는 로컬 시간을 반환합니다. UTC의 경우 항상 tz=timezone.utc를 전달하세요.

타임존 처리

Naive datetime(타임존 정보 없음)은 버그의 일반적인 원인입니다. Python은 타임존 인식 datetime을 위한 두 가지 내장 접근 방식을 제공합니다.

datetime.timezone 사용 (내장)

timezone 클래스는 고정 UTC 오프셋을 처리합니다.

from datetime import datetime, timezone, timedelta
 
# UTC
utc_now = datetime.now(timezone.utc)
print(utc_now)  # 2026-02-10 14:30:00+00:00
 
# 고정 오프셋 (예: 인도의 UTC+5:30)
ist = timezone(timedelta(hours=5, minutes=30))
india_time = datetime.now(ist)
print(india_time)  # 2026-02-10 20:00:00+05:30
 
# 타임존 간 변환
utc_time = datetime(2026, 3, 15, 12, 0, 0, tzinfo=timezone.utc)
eastern = timezone(timedelta(hours=-5))
eastern_time = utc_time.astimezone(eastern)
print(eastern_time)  # 2026-03-15 07:00:00-05:00

zoneinfo 사용 (Python 3.9+)

서머타임을 올바르게 처리하는 명명된 타임존에는 zoneinfo 모듈을 사용합니다.

from datetime import datetime
from zoneinfo import ZoneInfo
 
# 명명된 타임존
utc = ZoneInfo("UTC")
eastern = ZoneInfo("America/New_York")
tokyo = ZoneInfo("Asia/Tokyo")
 
# 타임존 인식 datetime 생성
dt = datetime(2026, 7, 15, 12, 0, 0, tzinfo=utc)
print(dt)  # 2026-07-15 12:00:00+00:00
 
# 다른 타임존으로 변환
print(dt.astimezone(eastern))  # 2026-07-15 08:00:00-04:00 (EDT)
print(dt.astimezone(tokyo))    # 2026-07-15 21:00:00+09:00

Naive vs Aware Datetime

특성NaiveAware
타임존 정보 있음아니오
존 간 비교에서 안전아니오
datetime.now()로 생성아니오 (tz 전달 시 제외)
연산에서 혼합 가능다른 naive와만다른 aware와만
프로덕션에서 권장아니오

naive datetime과 aware datetime을 비교하거나 빼는 것은 불가능합니다. Python은 TypeError를 발생시킵니다.

실용적인 예제

사람의 나이 계산

from datetime import date
 
def calculate_age(birth_date):
    """Calculate age in years from a birth date."""
    today = date.today()
    age = today.year - birth_date.year
    if (today.month, today.day) < (birth_date.month, birth_date.day):
        age -= 1
    return age
 
birthday = date(1995, 8, 20)
print(f"Age: {calculate_age(birthday)} years")  # Age: 30 years (as of Feb 2026)

날짜 범위 생성

from datetime import date, timedelta
 
def date_range(start, end, step_days=1):
    """Generate dates from start to end (inclusive)."""
    current = start
    while current <= end:
        yield current
        current += timedelta(days=step_days)
 
start = date(2026, 2, 1)
end = date(2026, 2, 7)
 
for d in date_range(start, end):
    print(d.strftime("%A, %B %d"))

두 날짜 사이의 영업일 수 세기

from datetime import date, timedelta
 
def business_days_between(start, end):
    """Count weekdays (Mon-Fri) between two dates, excluding endpoints."""
    count = 0
    current = start + timedelta(days=1)
    while current < end:
        if current.weekday() < 5:  # 0=Mon, 4=Fri
            count += 1
        current += timedelta(days=1)
    return count
 
start = date(2026, 2, 1)
end = date(2026, 2, 28)
print(f"Business days: {business_days_between(start, end)}")  # Business days: 19

Jupyter에서 Datetime 실험하기

날짜와 시간 연산은 인터랙티브한 실험에서 큰 이점을 얻습니다. CSV에서 일관되지 않은 날짜 형식을 파싱하거나 타임존 변환을 디버깅할 때, 노트북 셀에서 각 단계를 테스트할 수 있으면 상당한 시간을 절약할 수 있습니다.

RunCell (opens in a new tab)은 Jupyter 노트북 내에서 직접 작동하는 AI 에이전트입니다. datetime 객체를 검사하고, 데이터에 적합한 strftime/strptime 포맷 코드를 제안하며, 타임존 변환 문제를 실시간으로 디버깅하는 데 도움을 줍니다.

strftime vs strptime: 빠른 비교

strftimestrptime
전체 이름String Format TimeString Parse Time
방향datetime -> 문자열문자열 -> datetime
호출 대상datetime 객체datetime 클래스
구문dt.strftime("%Y-%m-%d")datetime.strptime(s, "%Y-%m-%d")
반환포맷된 문자열datetime 객체
예외없음포맷 불일치 시 ValueError
사용 사례표시, 로깅, 파일 이름CSV, API 응답, 사용자 입력 파싱
from datetime import datetime
 
# strftime: datetime -> string
dt = datetime(2026, 3, 15, 9, 30)
formatted = dt.strftime("%B %d, %Y at %I:%M %p")
print(formatted)  # March 15, 2026 at 09:30 AM
 
# strptime: string -> datetime
parsed = datetime.strptime("March 15, 2026 at 09:30 AM", "%B %d, %Y at %I:%M %p")
print(parsed)  # 2026-03-15 09:30:00

FAQ

Python에서 현재 날짜와 시간을 가져오려면?

datetime 모듈의 datetime.now()를 사용하세요. 날짜만 필요하면 date.today()를 사용하세요. 타임존 인식 현재 시간의 경우 타임존을 전달하세요: datetime.now(tz=timezone.utc). 이것들은 표준 접근 방식이며 서드파티 라이브러리가 필요하지 않습니다.

Python에서 strftime과 strptime의 차이는?

strftime은 datetime 객체를 포맷된 문자열로 변환합니다(string from time). strptime은 문자열을 파싱하여 datetime 객체로 변환합니다(string parse time). strftime은 문자열을 출력하고, strptime은 문자열을 입력한다고 기억하세요. 둘 다 %Y, %m, %d와 같은 동일한 포맷 코드를 사용합니다.

Python에서 날짜에 일수를 추가하려면?

timedelta 클래스를 사용하세요. datetime에서 임포트한 후 날짜에 더하세요: new_date = old_date + timedelta(days=7). weeks, hours, minutes, seconds도 매개변수로 사용할 수 있습니다. 빼기도 같은 방식으로 작동합니다: past_date = today - timedelta(days=30).

Python에서 문자열을 datetime으로 변환하려면?

datetime.strptime(string, format)을 사용하세요. 입력과 일치하는 포맷 문자열을 제공해야 합니다. 예를 들어, datetime.strptime("2026-03-15", "%Y-%m-%d")는 ISO 날짜를 파싱합니다. 문자열이 포맷과 일치하지 않으면 Python은 ValueError를 발생시키므로, 외부 데이터의 경우 호출을 try/except 블록으로 감싸세요.

Python datetime에서 타임존을 처리하려면?

Python 3.9 이상에서는 내장 zoneinfo 모듈을 사용하세요: from zoneinfo import ZoneInfo. datetime.now(tz=ZoneInfo("UTC"))로 타임존 인식 datetime을 생성하고 dt.astimezone(ZoneInfo("America/New_York"))으로 존 간 변환을 수행하세요. 고정 UTC 오프셋에는 datetime.timezone(timedelta(hours=N))을 사용하세요. 프로덕션 코드에서는 naive datetime을 피하세요.

결론

Python의 datetime 모듈은 날짜와 시간 연산에 필요한 모든 것을 제공합니다: 날짜 생성, 표시를 위한 포맷팅, 문자열에서 파싱, 연산 수행, 타임존 처리. 핵심 패턴은 한번 배우면 일관되고 예측 가능합니다.

핵심 구분을 기억하세요: strftime은 datetime을 문자열로 포맷하고, strptime은 문자열을 datetime으로 파싱합니다. 날짜 연산에는 timedelta를 사용하세요. 올바른 타임존 처리에는 zoneinfo (Python 3.9+)를 사용하세요. 미묘한 비교 버그를 피하기 위해 프로덕션 코드에서는 datetime을 타임존 인식으로 유지하세요.

대부분의 프로젝트에서는 내장 datetime 모듈로 충분합니다. 현대 Python에서는 pytz가 필요하지 않습니다 -- zoneinfo가 명명된 타임존을 네이티브로 처리합니다. datetime.now(tz=timezone.utc)를 기준점으로 시작하고, 사용자에게 표시할 때만 로컬 타임존으로 변환하세요.

📚