Pythonμ datetime μκ°λ μ²λ¦¬ 볡μ‘μ±μ νν€μΉμΈμ. κ°λ ₯νκ³ κΈλ‘λ²μ μΈμνλ μ ν리μΌμ΄μ μ μν΄ UTC λ³ν λ° μ§μνλ₯Ό μμ μκ² κ΄λ¦¬νκ³ μ νμ±κ³Ό μ¬μ©μ λ§μ‘±λλ₯Ό 보μ₯νλ λ°©λ²μ μμ보μΈμ.
Python Datetime μκ°λ μ²λ¦¬ λ§μ€ν°νκΈ°: κΈλ‘λ² μ ν리μΌμ΄μ μ μν UTC λ³ν vs. μ§μν
μ€λλ μνΈ μ°κ²°λ μΈμμμ μννΈμ¨μ΄ μ ν리μΌμ΄μ μ λ¨μΌ μκ°λμ μ μ½ μμμ μλνλ κ²½μ°κ° λλ λλ€. λλ₯ κ° νμ μΌμ μ μ‘κ±°λ λ€μν μ§λ¦¬μ μμμ κ±Έμ³ μ¬μ©μλ₯Ό μν΄ μ€μκ° μ΄λ²€νΈλ₯Ό μΆμ νλ λ±, μ νν μκ° κ΄λ¦¬κ° 무μλ³΄λ€ μ€μν©λλ€. λ μ§μ μκ°μ μ²λ¦¬νλ λ° μλͺ»λ κ²°μ μ νΌλμ€λ¬μ΄ λ°μ΄ν°, λΆμ νν κ³μ°, λ§κ°μΌ λμΉ¨, κ·Έλ¦¬κ³ κΆκ·Ήμ μΌλ‘ μ’μ κ°μ λλΌλ μ¬μ©μ κΈ°λ°μ μ΄λν μ μμ΅λλ€. λ°λ‘ μ¬κΈ°μ Pythonμ κ°λ ₯ν datetime λͺ¨λμ΄ κ°λ ₯ν μκ°λ λΌμ΄λΈλ¬λ¦¬μ κ²°ν©λμ΄ μ루μ μ μ 곡ν©λλ€.
μ΄ ν¬κ΄μ μΈ κ°μ΄λλ Pythonμ μκ°λ μ²λ¦¬ λ°©μμ λ―Έλ¬ν μ°¨μ΄λ₯Ό κΉμ΄ νκ³ λ€μ΄, UTC λ³νκ³Ό μ§μνλΌλ λ κ°μ§ κΈ°λ³Έ μ λ΅μ μ€μ μ λ‘λλ€. λ°±μλ μ΄μ λ° λ°μ΄ν° μ μ₯μ μμ΄ κ΅μ νμ€μΈ νμ μΈκ³μ(UTC)κ° μ νμμ μΈμ§, κ·Έλ¦¬κ³ μ§κ΄μ μΈ μ¬μ©μ κ²½νμ μ 곡νκΈ° μν΄ λ‘컬 μκ°λλ‘ λ³ννκ³ κ·Έ λ°λλ‘ λ³ννλ κ²μ΄ μ μ€μνμ§ μ΄ν΄λ΄ λλ€. κΈλ‘λ² μ μ μκ±°λ νλ«νΌ, νμ μμ°μ± λꡬ λλ κ΅μ λ°μ΄ν° λΆμ μμ€ν μ ꡬμΆνλ , μ΄λ¬ν κ°λ μ μ΄ν΄νλ κ²μ μ¬μ©μμ μμΉμ κ΄κ³μμ΄ μ ν리μΌμ΄μ μ΄ μ λ°νκ³ μ°μνκ² μκ°μ μ²λ¦¬νλλ‘ λ³΄μ₯νλ λ° νμμ μ λλ€.
κΈλ‘λ² λ§₯λ½μμμ μκ° λ¬Έμ
λμΏμ μλ μ¬μ©μκ° λ΄μμ μλ λλ£μ νμ ν΅νλ₯Ό μμ½νλ€κ³ μμν΄ λ³΄μΈμ. μ ν리μΌμ΄μ μ΄ μκ°λ μ 보 μμ΄ λ¨μν "5μ 1μΌ μ€μ 9μ"λ₯Ό μ μ₯νλ€λ©΄ νΌλμ΄ λ°μν©λλ€. λμΏ μκ° μ€μ 9μμΈκ°μ, λ΄μ μκ° μ€μ 9μμΈκ°μ, μλλ©΄ λ€λ₯Έ κ²μΈκ°μ? μ΄λ¬ν λͺ¨νΈμ±μ μκ°λ μ²λ¦¬κ° ν΄κ²°νλ ν΅μ¬ λ¬Έμ μ λλ€.
μκ°λλ λ¨μν UTCμμ λ²μ΄λ κ³ μ λ μ€νμ μ΄ μλλλ€. μ΄λ μ μΉμ κ²°μ , μ§λ¦¬μ κ²½κ³ λ° μμ¬μ μ λ‘μ μν₯μ λ°λ 볡μ‘νκ³ λμμμ΄ λ³ννλ μ€μ²΄μ λλ€. λ€μμ 볡μ‘μ±μ κ³ λ €ν΄ λ³΄μΈμ.
- μΌκ΄ μ μ½ μκ°μ (DST): λ§μ μ§μμμ DSTλ₯Ό μ€μνλ©°, μ°μ€ νΉμ μκΈ°μ μκ³λ₯Ό 1μκ°(λλ λλ‘λ λ λ§κ±°λ μ κ²) μλΉκΈ°κ±°λ λ€λ‘ μ‘°μ ν©λλ€. μ΄λ λ¨μΌ μ€νμ μ΄ 1λ μ μΌλΆ κΈ°κ°μλ§ μ ν¨ν μ μμμ μλ―Έν©λλ€.
- μ μΉμ λ° μμ¬μ λ³κ²½: κ΅κ°λ€μ μκ°λ κ·μΉμ μμ£Ό λ³κ²½ν©λλ€. κ΅κ²½μ΄ μ΄λνκ³ , μ λΆκ° DSTλ₯Ό μ±ννκ±°λ ν¬κΈ°νκΈ°λ‘ κ²°μ νκ±°λ, νμ€ μ€νμ μ λ³κ²½νκΈ°λ ν©λλ€. μ΄λ¬ν λ³κ²½μ νμ μμΈ‘ κ°λ₯νμ§ μμΌλ©° μ΅μ μκ°λ λ°μ΄ν°κ° νμν©λλ€.
- λͺ¨νΈμ±: DSTμ "κ°μ μ ν" μ€μ λμΌν μκ³ μκ°μ΄ λ λ² λ°μν μ μμ΅λλ€. μλ₯Ό λ€μ΄, μ€μ 1μ 30λΆμ΄ λ μ μκ³ , ν μκ° ν μκ³κ° λ€μ μ€μ 1μλ‘ λμκ°λ©΄ μ€μ 1μ 30λΆμ΄ λ€μ λ°μν©λλ€. νΉμ κ·μΉμ΄ μμΌλ©΄ μ΄λ¬ν μκ°μ λͺ¨νΈν©λλ€.
- μ‘΄μ¬νμ§ μλ μκ°: "λ΄ μ ν" μ€μ ν μκ°μ΄ 건λλλλ€. μλ₯Ό λ€μ΄, μκ³κ° μ€μ 1μ 59λΆμμ μ€μ 3μλ‘ κ±΄λλΈ μ μμΌλ―λ‘ ν΄λΉ νΉμ μμΌμλ μ€μ 2μ 30λΆκ³Ό κ°μ μκ°μ΄ μ‘΄μ¬νμ§ μκ² λ©λλ€.
- λ€μν μ€νμ : μκ°λλ νμ μ μ μκ° λ¨μκ° μλλλ€. μΌλΆ μ§μμμλ UTC+5:30 (μΈλ) λλ UTC+8:45 (νΈμ£Ό μΌλΆ μ§μ)κ³Ό κ°μ μ€νμ μ μ€μν©λλ€.
μ΄λ¬ν 볡μ‘μ±μ 무μνλ©΄ μλͺ»λ λ°μ΄ν° λΆμλΆν° μμ½ μΆ©λ, κ·μ μ°μ μ κ·μ μ€μ λ¬Έμ μ μ΄λ₯΄κΈ°κΉμ§ μ¬κ°ν μ€λ₯κ° λ°μν μ μμ΅λλ€. Pythonμ μ΄λ¬ν 볡μ‘ν νκ²½μ ν¨κ³Όμ μΌλ‘ νμν μ μλ λꡬλ₯Ό μ 곡ν©λλ€.
Pythonμ datetime λͺ¨λ: κΈ°μ΄
Pythonμ λ μ§ λ° μκ° κΈ°λ₯μ ν΅μ¬μ λ΄μ₯ datetime λͺ¨λμ λλ€. μ΄ λͺ¨λμ κ°λ¨νκ³ λ³΅μ‘ν λ°©μμΌλ‘ λ μ§μ μκ°μ μ‘°μνλ ν΄λμ€λ₯Ό μ 곡ν©λλ€. μ΄ λͺ¨λμμ κ°μ₯ μΌλ°μ μΌλ‘ μ¬μ©λλ ν΄λμ€λ datetime.datetimeμ λλ€.
Naive vs. Aware datetime κ°μ²΄
μ΄ κ΅¬λΆμ Pythonμ μκ°λ μ²λ¦¬μμ κ°μ₯ μ€μν κ°λ μ΄λΌκ³ ν μ μμ΅λλ€:
- Naive datetime κ°μ²΄: μ΄ κ°μ²΄μλ μκ°λ μ λ³΄κ° ν¬ν¨λμ΄ μμ§ μμ΅λλ€. λ¨μν λ μ§μ μκ°μ λνλ λλ€ (μ: 2023-10-27 10:30:00). μκ°λλ₯Ό λͺ μμ μΌλ‘ μ°κ²°νμ§ μκ³ datetime κ°μ²΄λ₯Ό μμ±νλ©΄ κΈ°λ³Έμ μΌλ‘ naiveκ° λ©λλ€. λ°λμ 10:30:00μ λ΄μμ 10:30:00κ³Ό λ€λ₯Έ μ λμ μΈ μκ° ν¬μΈνΈμ΄λ―λ‘ λ¬Έμ κ° λ μ μμ΅λλ€.
- Aware datetime κ°μ²΄: μ΄ κ°μ²΄μλ λͺ μμ μΈ μκ°λ μ λ³΄κ° ν¬ν¨λμ΄ μμ΄ λͺ¨νΈνμ§ μμ΅λλ€. λ μ§μ μκ°λΏλ§ μλλΌ μν μκ°λμ μ€μνκ²λ UTCμμ μ€νμ μ μκ³ μμ΅λλ€. aware κ°μ²΄λ λ€λ₯Έ μ§λ¦¬μ μμΉμ κ±Έμ³ μ λμ μΈ μκ° ν¬μΈνΈλ₯Ό μ¬λ°λ₯΄κ² μλ³ν μ μμ΅λλ€.
tzinfo μμ±μ κ²μ¬νμ¬ datetime κ°μ²΄κ° awareμΈμ§ naiveμΈμ§ νμΈν μ μμ΅λλ€. tzinfoκ° Noneμ΄λ©΄ κ°μ²΄λ naiveμ λλ€. tzinfo κ°μ²΄μ΄λ©΄ awareμ λλ€.
Naive datetime μμ± μμ:
import datetime
naive_dt = datetime.datetime(2023, 10, 27, 10, 30, 0)
print(f"Naive datetime: {naive_dt}")
print(f"Is naive? {naive_dt.tzinfo is None}")
# μΆλ ₯:
# Naive datetime: 2023-10-27 10:30:00
# Is naive? True
Aware datetime μμ (κ³§ μ€λͺ ν pytz μ¬μ©):
import datetime
import pytz # μ΄ λΌμ΄λΈλ¬λ¦¬λ₯Ό μμΈν μ€λͺ
νκ² μ΅λλ€.
london_tz = pytz.timezone('Europe/London')
aware_dt = london_tz.localize(datetime.datetime(2023, 10, 27, 10, 30, 0))
print(f"Aware datetime: {aware_dt}")
print(f"Is naive? {aware_dt.tzinfo is None}")
# μΆλ ₯:
# Aware datetime: 2023-10-27 10:30:00+01:00
# Is naive? False
datetime.now() vs datetime.utcnow()
μ΄ λ λ©μλλ μ’ μ’ νΌλμ μμΈμ΄ λ©λλ€. λμμ λͺ νν ν΄λ΄ μλ€:
- datetime.datetime.now(): κΈ°λ³Έμ μΌλ‘ μμ€ν μκ³μ λ°λΌ νμ¬ λ‘컬 μκ°μ λνλ΄λ naive datetime κ°μ²΄λ₯Ό λ°νν©λλ€. tz=some_tzinfo_object (Python 3.3λΆν° μ¬μ© κ°λ₯)λ₯Ό μ λ¬νλ©΄ aware κ°μ²΄λ₯Ό λ°νν μ μμ΅λλ€.
- datetime.datetime.utcnow(): νμ¬ UTC μκ°μ λνλ΄λ naive datetime κ°μ²΄λ₯Ό λ°νν©λλ€. μ€μνκ²λ UTCμ΄κΈ΄ νμ§λ§, λͺ μμ μΈ tzinfo κ°μ²΄κ° μκΈ° λλ¬Έμ μ¬μ ν naiveμ λλ€. μ΄λ μ μ ν μ§μν μμ΄λ μ§μ λΉκ΅νκ±°λ λ³ννλ λ° μμ νμ§ μμ΅λλ€.
μ€ν κ°λ₯ν ν΅μ°°: μλ‘μ΄ μ½λ, νΉν κΈλ‘λ² μ ν리μΌμ΄μ μ κ²½μ° datetime.utcnow()λ₯Ό νΌνμμμ€. λμ datetime.datetime.now(datetime.timezone.utc) (Python 3.3+)λ₯Ό μ¬μ©νκ±°λ pytz λλ zoneinfoμ κ°μ μκ°λ λΌμ΄λΈλ¬λ¦¬λ₯Ό μ¬μ©νμ¬ datetime.datetime.now()λ₯Ό λͺ μμ μΌλ‘ μ§μννμμμ€.
UTC μ΄ν΄νκΈ°: 보νΈμ μΈ νμ€
νμ μΈκ³μ(UTC)λ μ μΈκ³κ° μκ³μ μκ°μ κ·μ νλ μ£Όμ μκ° νμ€μ λλ€. μ΄λ λ³Έμ§μ μΌλ‘ 그리λμΉ νκ· μ(GMT)μ νμμ΄λ©° μ μΈκ³μ μμμκ³ μ»¨μμμμ μν΄ μ μ§λ©λλ€. UTCμ μ£Όμ νΉμ§μ μ λμ μΈ μ±κ²©μ΄λΌλ κ²μ λλ€. μΌκ΄ μ μ½ μκ°μ λ₯Ό μ€μνμ§ μμΌλ©° μ°μ€ μΌμ νκ² μ μ§λ©λλ€.
κΈλ‘λ² μ ν리μΌμ΄μ μ UTCκ° νμμ μΈ μ΄μ
μ¬λ¬ μκ°λμ κ±Έμ³ μλν΄μΌ νλ λͺ¨λ μ ν리μΌμ΄μ μ λν΄ UTCλ μ΅κ³ μ μΉκ΅¬μ λλ€. κ·Έ μ΄μ λ λ€μκ³Ό κ°μ΅λλ€:
- μΌκ΄μ± λ° λͺ¨νΈμ± μμ: λͺ¨λ μκ°μ μ λ ₯ μ κ°λ₯ν ν 빨리 UTCλ‘ λ³ννκ³ UTCμ μ μ₯ν¨μΌλ‘μ¨ λͺ¨λ λͺ¨νΈμ±μ μ κ±°ν©λλ€. νΉμ UTC νμμ€ν¬νλ λ‘컬 μκ°λλ DST κ·μΉμ κ΄κ³μμ΄ λͺ¨λ μ¬μ©μμ λν΄ μ νν λμΌν μκ° μ§μ μ μ°Έμ‘°ν©λλ€.
- κ°μνλ λΉκ΅ λ° κ³μ°: λͺ¨λ νμμ€ν¬νκ° UTCμ μμΌλ©΄ λΉκ΅, κΈ°κ° κ³μ° λλ μ΄λ²€νΈ μ λ ¬μ΄ κ°λ¨ν΄μ§λλ€. λ€λ₯Έ μ€νμ μ΄λ DST μ νμ΄ λ Όλ¦¬μ κ°μνλ κ²μ λν΄ κ±±μ ν νμκ° μμ΅λλ€.
- κ°λ ₯ν μ μ₯: λ°μ΄ν°λ² μ΄μ€(νΉν TIMESTAMP WITH TIME ZONE κΈ°λ₯μ κ°μΆ λ°μ΄ν°λ² μ΄μ€)λ UTCλ₯Ό νμ©ν©λλ€. λ°μ΄ν°λ² μ΄μ€μ λ‘컬 μκ°μ μ μ₯νλ κ²μ μ¬μμ μμΈμ΄ λ μ μμ΅λλ€. λ‘컬 μκ°λ κ·μΉμ΄ λ³κ²½λκ±°λ μλ²μ μκ°λμ μλλ μκ°λκ° λ€λ₯Ό μ μκΈ° λλ¬Έμ λλ€.
- API ν΅ν©: λ§μ REST API λ° λ°μ΄ν° κ΅ν νμ(ISO 8601 λ±)μ νμμ€ν¬νκ° UTCμ¬μΌ νλ€κ³ λͺ μν©λλ€. μ’ μ’ "Z"("Zulu time", UTCμ λν κ΅°μ¬μ©μ΄)λ‘ νμλ©λλ€. μ΄ νμ€μ μ€μνλ©΄ ν΅ν©μ΄ λ¨μνλ©λλ€.
ν©κΈλ₯ : νμ μκ°μ UTCμ μ μ₯νμμμ€. μ¬μ©μμκ² νμν λλ§ λ‘컬 μκ°λλ‘ λ³ννμμμ€.
Pythonμμ UTC μμ νκΈ°
Pythonμμ UTCλ₯Ό ν¨κ³Όμ μΌλ‘ μ¬μ©νλ €λ©΄ UTC μκ°λμ νΉλ³ν μ€μ λ aware datetime κ°μ²΄λ‘ μμ ν΄μΌ ν©λλ€. Python 3.9 μ΄μ μλ pytz λΌμ΄λΈλ¬λ¦¬κ° μ¬μ€μμ νμ€μ΄μμ΅λλ€. Python 3.9λΆν°λ λ΄μ₯ zoneinfo λͺ¨λμ΄ νΉν UTCμ λν΄ λ κ°μνλ μ κ·Ό λ°©μμ μ 곡ν©λλ€.
UTC-Aware Datetime μμ±
Aware UTC datetime κ°μ²΄λ₯Ό λ§λλ λ°©λ²μ μ΄ν΄λ΄ μλ€:
datetime.timezone.utc μ¬μ© (Python 3.3+)
import datetime
# νμ¬ UTC aware datetime
now_utc_aware = datetime.datetime.now(datetime.timezone.utc)
print(f"Current UTC aware: {now_utc_aware}")
# νΉμ UTC aware datetime
specific_utc_aware = datetime.datetime(2023, 10, 27, 10, 30, 0, tzinfo=datetime.timezone.utc)
print(f"Specific UTC aware: {specific_utc_aware}")
# μΆλ ₯μλ UTC μ€νμ
μ λν΄ +00:00 λλ Zκ° ν¬ν¨λ©λλ€.
Python 3.3 μ΄μμ μ¬μ©νλ κ²½μ° aware UTC datetimeμ μ»λ κ°μ₯ κ°λ¨νκ³ κΆμ₯λλ λ°©λ²μ λλ€.
pytz μ¬μ© (μ΄μ Python λ²μ λλ λ€λ₯Έ μκ°λμ κ²°ν© μ)
λ¨Όμ pytzλ₯Ό μ€μΉν©λλ€: pip install pytz
import datetime
import pytz
# νμ¬ UTC aware datetime
now_utc_aware_pytz = datetime.datetime.now(pytz.utc)
print(f"Current UTC aware (pytz): {now_utc_aware_pytz}")
# νΉμ UTC aware datetime (naive datetimeμ μ§μν)
naive_dt = datetime.datetime(2023, 10, 27, 10, 30, 0)
specific_utc_aware_pytz = pytz.utc.localize(naive_dt)
print(f"Specific UTC aware (pytz localized): {specific_utc_aware_pytz}")
Naive Datetimesλ₯Ό UTCλ‘ λ³ν
μ’ μ’ μ΄μ μμ€ν μ΄λ λͺ μμ μΌλ‘ μκ°λ μΈμμ΄ μλ μ¬μ©μ μ λ ₯μμ naive datetime κ°μ²΄λ₯Ό λ°μ μ μμ΅λλ€. μ΄ naive datetimeμ΄ UTCλ₯Ό λνλ΄λ κ²μΌλ‘ μλ €μ§ κ²½μ° aware κ°μ²΄λ‘ λ§λ€ μ μμ΅λλ€:
import datetime
import pytz
naive_dt_as_utc = datetime.datetime(2023, 10, 27, 10, 30, 0) # μ΄ naive κ°μ²΄λ UTC μκ°μ λνλ
λλ€.
# datetime.timezone.utc μ¬μ© (Python 3.3+)
aware_utc_from_naive = naive_dt_as_utc.replace(tzinfo=datetime.timezone.utc)
print(f"Naive assumed UTC to Aware UTC: {aware_utc_from_naive}")
# pytz μ¬μ©
aware_utc_from_naive_pytz = pytz.utc.localize(naive_dt_as_utc)
print(f"Naive assumed UTC to Aware UTC (pytz): {aware_utc_from_naive_pytz}")
Naive datetimeμ΄ λ‘컬 μκ°μ λνλ΄λ κ²½μ° νλ‘μΈμ€λ μ½κ° λ€λ¦ λλ€. λ¨Όμ ν΄λΉ μκ°λμ κ²μΌλ‘ κ°μ νμ¬ μ§μνν λ€μ UTCλ‘ λ³νν©λλ€. μ΄λ μ§μν μΉμ μμ λ μμΈν μ€λͺ νκ² μ΅λλ€.
μ§μν: μ¬μ©μμκ² μκ° νμ
UTCλ λ°±μλ λ‘μ§ λ° μ μ₯μ μ΄μμ μ΄μ§λ§ μ¬μ©μμκ² μ§μ νμνλ €λ λ΄μ©μ μλλλ€. ν리μ μ¬μ©μλ "15:00 CET"λ₯Ό κΈ°λνλ©° "14:00 UTC"λ₯Ό κΈ°λνμ§ μμ΅λλ€. μ§μνλ λμ μκ°λμ μ€νμ λ° DST κ·μΉμ κ³ λ €νμ¬ μ λ UTC μκ°μ νΉμ λ‘컬 μκ° ννμΌλ‘ λ³ννλ νλ‘μΈμ€μ λλ€.
μ§μνμ μ£Όμ λͺ©νλ μ¬μ©μκ° μ§λ¦¬μ λ° λ¬Ένμ λ§₯λ½μμ μ¦μ μ΄ν΄ν μ μλ μ΅μν νμμΌλ‘ μκ°μ νμνμ¬ μ¬μ©μ κ²½νμ ν₯μμν€λ κ²μ λλ€.
Pythonμμ μ§μν μμ νκΈ°
λ¨μν UTCλ₯Ό λμ΄μλ μ§μ ν μκ°λ μ§μνλ₯Ό μν΄ Pythonμ μΈλΆ λΌμ΄λΈλ¬λ¦¬ λλ IANA(Internet Assigned Numbers Authority) μκ°λ λ°μ΄ν°λ² μ΄μ€(tzdataλΌκ³ λ ν¨)λ₯Ό ν΅ν©νλ μ΅μ λ΄μ₯ λͺ¨λμ μμ‘΄ν©λλ€. μ΄ λ°μ΄ν°λ² μ΄μ€μλ DST μ νμ ν¬ν¨ν λͺ¨λ λ‘컬 μκ°λμ κΈ°λ‘κ³Ό λ―Έλκ° ν¬ν¨λμ΄ μμ΅λλ€.
pytz λΌμ΄λΈλ¬λ¦¬
μλ λμ pytzλ Pythonμμ μκ°λλ₯Ό μ²λ¦¬νλ μ£Όμ λΌμ΄λΈλ¬λ¦¬μμΌλ©°, νΉν 3.9 μ΄μ λ²μ μ κ·Έλ μ΅λλ€. IANA λ°μ΄ν°λ² μ΄μ€μ aware datetime κ°μ²΄λ₯Ό μμ±νλ λ©μλλ₯Ό μ 곡ν©λλ€.
μ€μΉ
pip install pytz
μ¬μ© κ°λ₯ν μκ°λ λμ΄
pytzλ λ°©λν μκ°λ λͺ©λ‘μ λν μ‘μΈμ€λ₯Ό μ 곡ν©λλ€:
import pytz
# print(pytz.all_timezones) # μ΄ λͺ©λ‘μ λ§€μ° κΉλλ€!
print(f"λͺ κ°μ§ μΌλ°μ μΈ μκ°λ: {pytz.all_timezones[:5]}")
print(f"λͺ©λ‘μ Europe/Londonμ΄ μλμ?: {'Europe/London' in pytz.all_timezones}")
νΉμ μκ°λλ‘ Naive Datetime μ§μν
νΉμ λ‘컬 μκ°λλ₯Ό μν κ²μ΄λΌκ³ νμ€ν μλ naive datetime κ°μ²΄(μ: μ¬μ©μμ λ‘컬 μκ°μ κ°μ νλ μ¬μ©μ μ λ ₯ μμ)κ° μλ κ²½μ° λ¨Όμ ν΄λΉ μκ°λλ‘ μ§μνν΄μΌ ν©λλ€.
import datetime
import pytz
naive_time = datetime.datetime(2023, 10, 27, 10, 30, 0) # μ€μ 10:30, 2023λ
london_tz = pytz.timezone('Europe/London')
localized_london = london_tz.localize(naive_time)
print(f"λ°λμμ μ§μνλ¨: {localized_london}")
# μΆλ ₯: 2023-10-27 10:30:00+01:00 (10μ λ§ λ°λμ BST/GMT+1)
ny_tz = pytz.timezone('America/New_York')
localized_ny = ny_tz.localize(naive_time)
print(f"λ΄μμμ μ§μνλ¨: {localized_ny}")
# μΆλ ₯: 2023-10-27 10:30:00-04:00 (10μ λ§ λ΄μμ EDT/GMT-4)
λμΌν naive μκ°μΌλ‘ μμνμμλ λΆκ΅¬νκ³ λ€λ₯Έ μ€νμ (+01:00 λ -04:00)μ μ£Όλͺ©νμμμ€. μ΄λ localize()κ° μ§μ λ λ‘컬 컨ν μ€νΈμ λν datetimeμ awareνκ² λ§λλ λ°©λ²μ 보μ¬μ€λλ€.
Aware Datetime (μΌλ°μ μΌλ‘ UTC)μ λ‘컬 μκ°λλ‘ λ³ν
μ΄κ²μ νμλ₯Ό μν μ§μνμ ν΅μ¬μ λλ€. aware UTC datetime (ν¬λ§μ μΌλ‘ μ μ₯ν)μΌλ‘ μμνμ¬ μ¬μ©μκ° μνλ λ‘컬 μκ°λλ‘ λ³νν©λλ€.
import datetime
import pytz
# μ΄ UTC μκ°μ λ°μ΄ν°λ² μ΄μ€μμ κ²μνλ€κ³ κ°μ ν©λλ€.
utc_now = datetime.datetime.now(pytz.utc) # μμ UTC μκ°
print(f"νμ¬ UTC μκ°: {utc_now}")
# Europe/Berlin μκ°μΌλ‘ λ³ν
berlin_tz = pytz.timezone('Europe/Berlin')
berlin_time = utc_now.astimezone(berlin_tz)
print(f"λ² λ₯Όλ¦° μκ°: {berlin_time}")
# Asia/Kolkata μκ° (UTC+5:30)μΌλ‘ λ³ν
kolkata_tz = pytz.timezone('Asia/Kolkata')
kolkata_time = utc_now.astimezone(kolkata_tz)
print(f"μ½μΉ΄ν μκ°: {kolkata_time}")
astimezone() λ©μλλ λ§€μ° κ°λ ₯ν©λλ€. aware datetime κ°μ²΄λ₯Ό λ°μ μ§μ λ λμ μκ°λλ‘ λ³ννκ³ μ€νμ λ° DST λ³κ²½ μ¬νμ μλμΌλ‘ μ²λ¦¬ν©λλ€.
zoneinfo λͺ¨λ (Python 3.9+)
Python 3.9κ³Ό ν¨κ» zoneinfo λͺ¨λμ΄ νμ€ λΌμ΄λΈλ¬λ¦¬μ μΌλΆλ‘ λμ λμ΄ IANA μκ°λλ₯Ό μ²λ¦¬νκΈ° μν νλμ μ΄κ³ λ΄μ₯λ μ루μ μ μ 곡ν©λλ€. νΉν ZoneInfo κ°μ²΄ κ΄λ¦¬μ μμ΄ λ κ°μνλ APIλ‘ μΈν΄ μ νλ‘μ νΈμμ pytzλ³΄λ€ μ νΈλλ κ²½μ°κ° λ§μ΅λλ€.
zoneinfoλ‘ μκ°λ μ‘μΈμ€
import datetime
from zoneinfo import ZoneInfo
# μκ°λ κ°μ²΄ κ°μ Έμ€κΈ°
london_tz_zi = ZoneInfo("Europe/London")
new_york_tz_zi = ZoneInfo("America/New_York")
# νΉμ μκ°λλ‘ aware datetime μμ±
now_london = datetime.datetime.now(london_tz_zi)
print(f"νμ¬ λ°λ μκ°: {now_london}")
# μκ°λλ‘ νΉμ datetime μμ±
specific_dt = datetime.datetime(2023, 10, 27, 10, 30, 0, tzinfo=new_york_tz_zi)
print(f"λ΄μ νΉμ μκ°: {specific_dt}")
zoneinfoλ‘ μκ°λ κ° λ³ν
aware datetime κ°μ²΄κ° μμΌλ©΄ λ³ν λ©μ»€λμ¦μ pytzμ λμΌνλ©° astimezone() λ©μλλ₯Ό νμ©ν©λλ€.
import datetime
from zoneinfo import ZoneInfo
# UTC aware datetimeμΌλ‘ μμ
utc_time_zi = datetime.datetime.now(datetime.timezone.utc)
print(f"νμ¬ UTC μκ°: {utc_time_zi}")
london_tz_zi = ZoneInfo("Europe/London")
london_time_zi = utc_time_zi.astimezone(london_tz_zi)
print(f"λ°λ μκ°: {london_time_zi}")
tokyo_tz_zi = ZoneInfo("Asia/Tokyo")
tokyo_time_zi = utc_time_zi.astimezone(tokyo_tz_zi)
print(f"λμΏ μκ°: {tokyo_time_zi}")
Python 3.9μ κ²½μ°, zoneinfoλ λ΄μ₯ κΈ°λ₯κ³Ό μ΅μ Python κ΄νκ³Όμ μ λ ¬ λλΆμ μΌλ°μ μΌλ‘ μ νΈλλ μ νμ λλ€. μ΄μ Python λ²μ μ λν νΈνμ±μ΄ νμν μ ν리μΌμ΄μ μ κ²½μ° pytzλ μ¬μ ν κ°λ ₯ν μ΅μ μ λλ€.
UTC λ³ν vs. μ§μν: μ¬μΈ΅ λΆμ
UTC λ³νκ³Ό μ§μνμ ꡬλΆμ νλλ₯Ό μ ννλ κ²μ΄ μλλΌ μ ν리μΌμ΄μ μ λ°μ΄ν° νλ¦μ λ€λ₯Έ λΆλΆμμ κ°κ°μ μν μ μ΄ν΄νλ κ²μ λλ€.
UTCλ‘ λ³νν΄μΌ νλ κ²½μ°
μ ν리μΌμ΄μ μ λ°μ΄ν° νλ¦μμ κ°λ₯ν ν μΌμ° UTCλ‘ λ³ννμμμ€. μΌλ°μ μΌλ‘ λ€μ μ§μ μμ λ°μν©λλ€:
- μ¬μ©μ μ λ ₯: μ¬μ©μκ° λ‘컬 μκ°(μ: "μ€ν 3μμ νμ μμ½")μ μ 곡νλ κ²½μ° μ ν리μΌμ΄μ μ ν΄λΉ λ‘컬 μκ°λ(μ: νλ‘ν, λΈλΌμ°μ μ€μ λλ λͺ μμ μ νμμ)λ₯Ό μ¦μ κ²°μ νκ³ ν΄λΉ λ‘컬 μκ°μ UTC λ±κ°λ¬Όλ‘ λ³νν΄μΌ ν©λλ€.
- μμ€ν μ΄λ²€νΈ: νμμ€ν¬νκ° μμ€ν μ체μμ μμ±λ λλ§λ€ (μ: created_at λλ last_updated νλ) μ΄μμ μΌλ‘λ UTCμ μ§μ μμ±λκ±°λ μ¦μ UTCλ‘ λ³νλμ΄μΌ ν©λλ€.
- API μμ : μΈλΆ APIμμ νμμ€ν¬νλ₯Ό μμ νλ κ²½μ° μ€λͺ μλ₯Ό νμΈνμμμ€. λͺ μμ μΈ μκ°λ μ 보 μμ΄ λ‘컬 μκ°μ μ 곡νλ κ²½μ° UTCλ‘ λ³ννκΈ° μ μ μμ€ μκ°λλ₯Ό μΆλ‘ νκ±°λ ꡬμ±ν΄μΌ ν μ μμ΅λλ€. UTC(μ’ μ’ ISO 8601 νμμ "Z" ν¬ν¨)λ₯Ό μ 곡νλ κ²½μ° aware UTC κ°μ²΄λ‘ μ¬λ°λ₯΄κ² ꡬ문 λΆμν΄μΌ ν©λλ€.
- μ μ₯ μ : μꡬ μ μ₯(λ°μ΄ν°λ² μ΄μ€, νμΌ, μΊμ)μ μν λͺ¨λ νμμ€ν¬νλ UTCμ¬μΌ ν©λλ€. μ΄λ λ°μ΄ν° λ¬΄κ²°μ± λ° μΌκ΄μ±μ μν΄ λ§€μ° μ€μν©λλ€.
μ§μνν΄μΌ νλ κ²½μ°
μ§μνλ "μΆλ ₯" νλ‘μΈμ€μ λλ€. μΈκ° μ¬μ©μμκ² μ΄ν΄νκΈ° μ¬μ΄ λ§₯λ½μμ μκ° μ 보λ₯Ό νμν΄μΌ ν λ λ°μν©λλ€.
- μ¬μ©μ μΈν°νμ΄μ€ (UI): μΉ λλ λͺ¨λ°μΌ μ ν리μΌμ΄μ μμ μ΄λ²€νΈ μκ°, λ©μμ§ νμμ€ν¬ν λλ μμ½ μ¬λ‘―μ νμν©λλ€. μκ°μ μ¬μ©μκ° μ ννκ±°λ μΆλ‘ ν λ‘컬 μκ°λλ₯Ό λ°μν΄μΌ ν©λλ€.
- λ³΄κ³ μ λ° λΆμ: νΉμ μ§μ μ΄ν΄κ΄κ³μλ₯Ό μν λ³΄κ³ μ μμ±. μλ₯Ό λ€μ΄, μ λ½μ νλ§€ λ³΄κ³ μλ Europe/BerlinμΌλ‘ μ§μνλ μ μκ³ , λΆλ―Έμ λ³΄κ³ μλ America/New_Yorkμ μ¬μ©ν μ μμ΅λλ€.
- μ΄λ©μΌ μλ¦Ό: 미리 μλ¦Ό λλ νμΈ λ³΄λ΄κΈ°. λ΄λΆ μμ€ν μ UTCλ‘ μλνμ§λ§ μ΄λ©μΌ λ΄μ©μ λͺ νμ±μ μν΄ μμ μμ λ‘컬 μκ°μ μ¬μ©νλ κ²μ΄ μ’μ΅λλ€.
- μΈλΆ μμ€ν μΆλ ₯: μΈλΆ μμ€ν μ΄ νΉμ λ‘컬 μκ°λλ‘ νμμ€ν¬νλ₯Ό λͺ μμ μΌλ‘ μꡬνλ κ²½μ°(μ μ€κ³λ APIμλ λλ¬Όμ§λ§ λ°μν μ μμ), μ μ‘ μ μ μ§μνν©λλ€.
λ μ§ μκ°μ μ€λͺ μν¬νλ‘
κ°λ¨ν μλ리μ€λ₯Ό κ³ λ €ν΄ λ³΄κ² μ΅λλ€: μ¬μ©μκ° μ΄λ²€νΈλ₯Ό μμ½ν©λλ€.
- μ¬μ©μ μ λ ₯: μλλ, νΈμ£Ό(Australia/Sydney)μ μλ μ¬μ©μκ° "2023λ 11μ 5μΌ μ€ν 3μ νμ"λ₯Ό μ λ ₯ν©λλ€. ν΄λΌμ΄μΈνΈ μΈ‘ μ ν리μΌμ΄μ μ νμ¬ μκ°λ IDμ ν¨κ» μ΄ μ 보λ₯Ό naive λ¬Έμμ΄λ‘ λ³΄λΌ μ μμ΅λλ€.
- μλ² μμ λ° UTCλ‘ λ³ν:
import datetime
from zoneinfo import ZoneInfo # λλ import pytz
user_input_naive = datetime.datetime(2023, 11, 5, 15, 0, 0) # μ€ν 3μ
user_timezone_id = "Australia/Sydney"
user_tz = ZoneInfo(user_timezone_id)
localized_to_sydney = user_input_naive.replace(tzinfo=user_tz)
print(f"μ¬μ©μ μ λ ₯μ΄ μλλλ‘ μ§μνλ¨: {localized_to_sydney}")
# μ μ₯μ μν΄ UTCλ‘ λ³ν
utc_time_for_storage = localized_to_sydney.astimezone(datetime.timezone.utc)
print(f"μ μ₯μ μν΄ UTCλ‘ λ³νλ¨: {utc_time_for_storage}")
μ΄ μμ μμ utc_time_for_storageλ μ μ₯ν μ€λΉκ° λ aware UTC datetimeμ λλ€.
- λ°μ΄ν°λ² μ΄μ€ μ μ₯: utc_time_for_storageλ λ°μ΄ν°λ² μ΄μ€μ TIMESTAMP WITH TIME ZONE(λλ μ΄μ μμνλ κ²)μΌλ‘ μ μ₯λ©λλ€.
- κ²μ λ° νμλ₯Ό μν μ§μν: λμ€μ λ€λ₯Έ μ¬μ©μ(μ: λ² λ₯Όλ¦°, λ
μΌ - Europe/Berlin)κ° μ΄ μ΄λ²€νΈλ₯Ό λ΄
λλ€. μ ν리μΌμ΄μ
μ λ°μ΄ν°λ² μ΄μ€μμ UTC μκ°μ κ²μν©λλ€.
import datetime
from zoneinfo import ZoneInfo
# λ°μ΄ν°λ² μ΄μ€μμ κ²μλμμΌλ©° μ΄λ―Έ UTC awareλΌκ³ κ°μ
retrieved_utc_time = datetime.datetime(2023, 11, 5, 4, 0, 0, tzinfo=datetime.timezone.utc) # UTC μ€μ 4μ
print(f"κ²μλ UTC μκ°: {retrieved_utc_time}")
viewer_timezone_id = "Europe/Berlin"
viewer_tz = ZoneInfo(viewer_timezone_id)
display_time_for_berlin = retrieved_utc_time.astimezone(viewer_tz)
print(f"λ² λ₯Όλ¦° μ¬μ©μμκ² νμλ¨: {display_time_for_berlin}")
viewer_timezone_id_ny = "America/New_York"
viewer_tz_ny = ZoneInfo(viewer_timezone_id_ny)
display_time_for_ny = retrieved_utc_time.astimezone(viewer_tz_ny)
print(f"λ΄μ μ¬μ©μμκ² νμλ¨: {display_time_for_ny}")
μλλ μ€ν 3μμλ μ΄λ²€νΈλ μ΄μ λ¨μΌμ λͺ¨νΈνμ§ μμ UTC νμμ€ν¬νμμ νμλ λ² λ₯Όλ¦° μ€μ 5μ, λ΄μ μμ μΌλ‘ μ¬λ°λ₯΄κ² νμλ©λλ€.
μ€μ μλλ¦¬μ€ λ° μΌλ°μ μΈ ν¨μ
κ²¬κ³ ν μ΄ν΄λ₯Ό κ°μ§κ³ μμ΄λ μ€μ μ ν리μΌμ΄μ μ κ³ μ ν λ¬Έμ λ₯Ό μ μν©λλ€. μΌλ°μ μΈ μλ리μ€μ μ μ¬μ μ€λ₯λ₯Ό νΌνλ λ°©λ²μ μ΄ν΄λ΄ μλ€.
μμ½λ μμ λ° Cron μμ
μμ μ μμ½ν λ(μ: μΌκ° λ°μ΄ν° λ°±μ , μ΄λ©μΌ μμ½) μΌκ΄μ±μ΄ μ€μν©λλ€. νμ μλ²μμ UTCλ‘ μμ½ μκ°μ μ μνμμμ€.
- cron μμ λλ μμ μ€μΌμ€λ¬κ° νΉμ λ‘컬 μκ°λμμ μ€νλλ κ²½μ° UTCλ₯Ό μ¬μ©νλλ‘ κ΅¬μ±νκ±°λ μμ½μ λν΄ μλν UTC μκ°μ μλ²μ λ‘컬 μκ°μΌλ‘ λͺ μμ μΌλ‘ λ³ννλλ‘ νμμμ€.
- μμ½λ μμ μ λν Python μ½λ λ΄μμ νμ UTCλ₯Ό μ¬μ©νμ¬ νμμ€ν¬νλ₯Ό λΉκ΅νκ±°λ μμ±νμμμ€. μλ₯Ό λ€μ΄, λ§€μΌ μ€μ 2μ UTCμ μμ μ μ€ννλ €λ©΄:
import datetime
from zoneinfo import ZoneInfo # λλ pytz
current_utc_time = datetime.datetime.now(datetime.timezone.utc)
scheduled_hour_utc = 2 # UTC μ€μ 2μ
if current_utc_time.hour == scheduled_hour_utc and current_utc_time.minute == 0:
print("UTC μ€μ 2μμ
λλ€. μΌμΌ μμ
μ€ν μκ°!")
λ°μ΄ν°λ² μ΄μ€ μ μ₯ κ³ λ € μ¬ν
λλΆλΆμ μ΅μ λ°μ΄ν°λ² μ΄μ€λ κ°λ ₯ν datetime μ νμ μ 곡ν©λλ€:
- TIMESTAMP WITHOUT TIME ZONE: Pythonμ naive datetimeκ³Ό μ μ¬νκ² λ μ§μ μκ°λ§ μ μ₯ν©λλ€. κΈλ‘λ² μ ν리μΌμ΄μ μμλ μ΄λ₯Ό νΌνμμμ€.
- TIMESTAMP WITH TIME ZONE: (μ: PostgreSQL, Oracle) λ μ§, μκ° λ° μκ°λ μ 보(λλ μ½μ μ UTCλ‘ λ³ν)λ₯Ό μ μ₯ν©λλ€. μ΄λ μ νΈλλ μ νμ λλ€. κ²μν λ λ°μ΄ν°λ² μ΄μ€λ μΈμ λλ μλ²μ μκ°λλ‘ λ€μ λ³ννλ κ²½μ°κ° λ§μΌλ―λ‘ λ°μ΄ν°λ² μ΄μ€ λλΌμ΄λ²κ° μ΄λ₯Ό μ²λ¦¬νλ λ°©μμ μ£Όμνμμμ€. UTC λ°νμ μ§μνλ κ²μ΄ μ’ μ’ λ μμ ν©λλ€.
μ΅μμ λ°©λ²: ORM λλ λ°μ΄ν°λ² μ΄μ€ λλΌμ΄λ²μ μ λ¬νλ datetime κ°μ²΄κ° νμ aware UTC datetimeμΈμ§ νμΈνμμμ€. κ·Έλ° λ€μ λ°μ΄ν°λ² μ΄μ€λ μ μ₯μ μ¬λ°λ₯΄κ² μ²λ¦¬νκ³ λ λ§μ μ²λ¦¬λ₯Ό μν΄ aware UTC κ°μ²΄λ‘ κ²μν μ μμ΅λλ€.
API μνΈ μμ© λ° νμ€ νμ
μΈλΆ APIμ ν΅μ νκ±°λ μ체 APIλ₯Ό ꡬμΆν λ ISO 8601κ³Ό κ°μ νμ€μ μ€μνμμμ€:
- λ°μ΄ν° μ μ‘: λ΄λΆ UTC aware datetimeμ "Z" μ λ―Έμ¬(UTCμ©) λλ λͺ μμ μ€νμ (μ: 2023-10-27T10:30:00Z λλ 2023-10-27T12:30:00+02:00)κ° μλ ISO 8601 λ¬Έμμ΄λ‘ λ³νν©λλ€.
- λ°μ΄ν° μμ : Pythonμ datetime.datetime.fromisoformat() (Python 3.7+) λλ dateutil.parser.isoparse()μ κ°μ νμλ₯Ό μ¬μ©νμ¬ ISO 8601 λ¬Έμμ΄μ aware datetime κ°μ²΄λ‘ μ§μ λ³νν©λλ€.
import datetime
from dateutil import parser # pip install python-dateutil
# UTC aware datetimeμμ ISO 8601 λ¬Έμμ΄λ‘
my_utc_dt = datetime.datetime.now(datetime.timezone.utc)
iso_string = my_utc_dt.isoformat()
print(f"APIμ© ISO λ¬Έμμ΄: {iso_string}") # μ: 2023-10-27T10:30:00.123456+00:00
# APIμμ μμ ν ISO 8601 λ¬Έμμ΄μμ aware datetimeμΌλ‘
api_iso_string = "2023-10-27T10:30:00Z" # λλ "2023-10-27T12:30:00+02:00"
received_dt = parser.isoparse(api_iso_string) # μλμΌλ‘ aware datetime μμ±
print(f"μμ λ aware datetime: {received_dt}")
μΌκ΄ μ μ½ μκ°μ (DST) κ³Όμ
DST μ νμ μκ°λ μ²λ¦¬μ 골칫거리μ λλ€. λ κ°μ§ νΉμ λ¬Έμ λ₯Ό μΌκΈ°ν©λλ€:
- λͺ¨νΈν μκ° (κ°μ μ ν): μκ³κ° λ€λ‘ κ° λ(μ: μ€μ 2μμμ μ€μ 1μλ‘) ν μκ°μ΄ λ°λ³΅λ©λλ€. ν΄λΉ λ μ§μ μ¬μ©μκ° "μ€μ 1μ 30λΆ"μ μ λ ₯νλ©΄ μ΄λ 1μ 30λΆμ μλ―Ένλμ§ λΆλΆλͺ ν©λλ€. pytz.localize()μλ μ΄λ₯Ό μ²λ¦¬νλ is_dst λ§€κ°λ³μκ° μμ΅λλ€: λ λ²μ§Έ λ°μμ κ²½μ° is_dst=True, 첫 λ²μ§Έ λ°μμ κ²½μ° is_dst=False, λͺ¨νΈν κ²½μ° μ€λ₯λ₯Ό λ°μμν€λ €λ©΄ is_dst=None. zoneinfoλ κΈ°λ³Έμ μΌλ‘ μ΄λ₯Ό λ μ μ²λ¦¬νλ©°, μ’ μ’ λ λΉ λ₯Έ μκ°μ μ νν λ€μ foldλ₯Ό νμ©ν©λλ€.
- μ‘΄μ¬νμ§ μλ μκ° (λ΄ μ ν): μκ³κ° μμΌλ‘ κ° λ(μ: μ€μ 2μμμ μ€μ 3μλ‘) ν μκ°μ΄ 건λλλλ€. ν΄λΉ λ μ§μ μ¬μ©μκ° "μ€μ 2μ 30λΆ"μ μ λ ₯νλ©΄ ν΄λΉ μκ°μ μ‘΄μ¬νμ§ μμ΅λλ€. pytz.localize()μ ZoneInfo λͺ¨λ μΌλ°μ μΌλ‘ μ€λ₯λ₯Ό λ°μμν€κ±°λ κ°μ₯ κ°κΉμ΄ μ ν¨ν μκ°μΌλ‘ μ‘°μ νλ €κ³ μλν©λλ€(μ: μ€μ 3μλ‘ μ΄λ).
μν: μ΄λ¬ν ν¨μ μ νΌνλ κ°μ₯ μ’μ λ°©λ²μ κ°λ₯ν κ²½μ° νλ‘ νΈμλμμ UTC νμμ€ν¬νλ₯Ό μμ§νκ±°λ κ·Έλ μ§ μμ κ²½μ° λ‘컬 μκ° μ λ ₯κ³Ό ν¨κ» μ¬μ©μμ νΉμ μκ°λ κΈ°λ³Έ μ€μ μ νμ μ μ₯ν λ€μ μ£Όμ κΉκ² μ§μννλ κ²μ λλ€.
Naive Datetimesμ μν
μκ°λ λ²κ·Έλ₯Ό λ°©μ§νλ 첫 λ²μ§Έ κ·μΉμ λ€μκ³Ό κ°μ΅λλ€: μκ°λκ° κ΄λ ¨λ κ²½μ° naive datetime κ°μ²΄λ‘ κ³μ°μ΄λ λΉκ΅λ₯Ό μ λ μννμ§ λ§μμμ€. μ λμ μΈ μκ° ν¬μΈνΈμ μμ‘΄νλ μμ μ μννκΈ° μ μ νμ datetime κ°μ²΄κ° awareμΈμ§ νμΈνμμμ€.
- μμ μμ aware λ° naive datetimeμ νΌν©νλ©΄ TypeErrorκ° λ°μν©λλ€. μ΄λ Pythonμ΄ λͺ¨νΈν κ³μ°μ λ°©μ§νλ λ°©λ²μ λλ€.
κΈλ‘λ² μ ν리μΌμ΄μ μ μν λͺ¨λ² μ¬λ‘
μμ½νκ³ μ€ν κ°λ₯ν μ‘°μΈμ μ 곡νκΈ° μν΄ κΈλ‘λ² Python μ ν리μΌμ΄μ μμ datetimeμ μ²λ¦¬νκΈ° μν λͺ¨λ² μ¬λ‘λ λ€μκ³Ό κ°μ΅λλ€:
- Aware Datetimes μ¬μ©: μ λμ μΈ μκ° ν¬μΈνΈλ₯Ό λνλ΄λ λͺ¨λ datetime κ°μ²΄κ° awareμΈμ§ νμΈνμμμ€. μ μ ν μκ°λ κ°μ²΄λ₯Ό μ¬μ©νμ¬ tzinfo μμ±μ μ€μ νμμμ€.
- UTCμ μ μ₯: λ€μ΄μ€λ λͺ¨λ νμμ€ν¬νλ₯Ό μ¦μ UTCλ‘ λ³ννκ³ λ°μ΄ν°λ² μ΄μ€, μΊμ λλ λ΄λΆ μμ€ν μ UTCλ‘ μ μ₯νμμμ€. μ΄κ²μ΄ μ¬λ¬λΆμ μ μΌν μ§μ€ 곡κΈμμ λλ€.
- λ‘컬 μκ°μ νμ: μ¬μ©μμκ² μκ°μ νμν λλ§ UTCμμ μ¬μ©μμ κΈ°λ³Έ λ‘컬 μκ°λλ‘ λ³ννμμμ€. μ¬μ©μ νλ‘νμμ μκ°λ κΈ°λ³Έ μ€μ μ μ€μ νλλ‘ νμ©νμμμ€.
- κ°λ ₯ν μκ°λ λΌμ΄λΈλ¬λ¦¬ μ¬μ©: Python 3.9μ κ²½μ° zoneinfoλ₯Ό μ νΈνμμμ€. μ΄μ λ²μ μ΄λ νΉμ νλ‘μ νΈ μꡬ μ¬νμ κ²½μ° pytzκ° νλ₯ν©λλ€. DSTκ° κ΄λ ¨λ κ²½μ° μ¬μ©μ μ§μ μκ°λ λ Όλ¦¬ λλ κ°λ¨ν κ³ μ μ€νμ μ νΌνμμμ€.
- API ν΅μ νμ€ν: λͺ¨λ API μ λ ₯ λ° μΆλ ₯μ λν΄ ISO 8601 νμ(UTCμ κ²½μ° "Z" ν¬ν¨)μ μ¬μ©νμμμ€.
- μ¬μ©μ μ λ ₯ μ ν¨μ± κ²μ¬: μ¬μ©μκ° λ‘컬 μκ°μ μ 곡νλ κ²½μ° νμ λͺ μμ μκ°λ μ νκ³Ό ν¨κ» μμ μ΄λ£¨κ±°λ μμ μ μΌλ‘ μΆλ‘ νμμμ€. λͺ¨νΈν μ λ ₯μμ λ²μ΄λλλ‘ μλ΄νμμμ€.
- μ² μ ν ν μ€νΈ: νΉν DST μ ν(λ΄ μ ν, κ°μ μ ν) λ° μμ κ°μ λ μ§μ κ°μ κ°μ₯μ리 μ¬λ‘μ μ΄μ μ λ§μΆ° λ€μν μκ°λμ κ±Έμ³ datetime λ Όλ¦¬λ₯Ό ν μ€νΈνμμμ€.
- νλ‘ νΈμλ μ£Όμ: μ΅μ μΉ μ ν리μΌμ΄μ μ JavaScriptμ Intl.DateTimeFormat APIλ₯Ό μ¬μ©νμ¬ ν΄λΌμ΄μΈνΈ μΈ‘μμ μκ°λ λ³νμ μ²λ¦¬νλ κ²½μ°κ° λ§μΌλ©° λ°±μλλ‘ UTC νμμ€ν¬νλ₯Ό 보λ λλ€. μ΄λ λ°±μλ λ Όλ¦¬λ₯Ό λ¨μνν μ μμ§λ§ μ μ€ν μ‘°μ μ΄ νμν©λλ€.
κ²°λ‘
μκ°λ μ²λ¦¬λ λΆλ΄μ€λ¬μΈ μ μμ§λ§, μ μ₯ λ° λ΄λΆ λ‘μ§μ μν UTC λ³ν μμΉκ³Ό μ¬μ©μ νμλ₯Ό μν μ§μν μμΉμ μ€μν¨μΌλ‘μ¨ μ§μ μΌλ‘ κ°λ ₯νκ³ κΈλ‘λ²μ μΈμνλ μ ν리μΌμ΄μ μ PythonμΌλ‘ ꡬμΆν μ μμ΅λλ€. ν΅μ¬μ aware datetime κ°μ²΄λ‘ μΌκ΄λκ² μμ νκ³ pytz λλ λ΄μ₯ zoneinfo λͺ¨λκ³Ό κ°μ κ°λ ₯ν κΈ°λ₯μ μ΄μ μ νμ©νλ κ²μ λλ€.
μ λμ μΈ μκ° ν¬μΈνΈ(UTC)μ λ€μν λ‘컬 ννμ μ°¨μ΄λ₯Ό μ΄ν΄ν¨μΌλ‘μ¨ μ ν리μΌμ΄μ μ΄ μ μΈκ³μ μΌλ‘ μννκ² μλνλλ‘ νμ¬ λ€μν κ΅μ μ¬μ©μ κΈ°λ°μ μ νν μ 보μ μ°μν κ²½νμ μ 곡ν μ μμ΅λλ€. μ²μλΆν° μ¬λ°λ₯Έ μκ°λ μ²λ¦¬μ ν¬μνλ©΄ λμ€μ κΉλ€λ‘μ΄ μκ° κ΄λ ¨ λ²κ·Έλ₯Ό λλ²κΉ νλ λ° λλ μλ§μ μκ°μ μ μ½ν μ μμ΅λλ€.
ν볡ν μ½λ© λμκ³ , νμμ€ν¬νκ° νμ μ ννκΈΈ λ°λλλ€!