파이썬 표준 라이브러리 만 사용하여 파이썬 UTC 날짜 시간을 현지 날짜 시간으로 변환 하시겠습니까?


189

datetime.utcnow ()를 사용하여 생성하고 데이터베이스에 유지되는 파이썬 날짜 시간 인스턴스가 있습니다.

표시를 위해 기본 로컬 시간대를 사용하여 데이터베이스에서 검색 한 datetime 인스턴스를 로컬 datetime으로 변환하려고합니다 (예 : datetime이 datetime.now ()를 사용하여 만든 것처럼).

파이썬 표준 라이브러리 만 사용하여 UTC 날짜 시간을 현지 날짜 시간으로 변환하려면 어떻게합니까 (예 : pytz 종속성 없음)?

한 가지 해결책은 datetime.astimezone (tz)을 사용하는 것 같지만 기본 현지 시간대를 어떻게 얻습니까?


데이터베이스에 시간이 지속 된 형식은 무엇입니까? 표준 형식 인 경우 변환 할 필요가 없을 수 있습니다.
Apalala

1
답변pytz 를 사용하는 간단한 방법을 보여줍니다 .
juan

답변:


275

Python 3.3 이상에서 :

from datetime import datetime, timezone

def utc_to_local(utc_dt):
    return utc_dt.replace(tzinfo=timezone.utc).astimezone(tz=None)

파이썬 2/3에서 :

import calendar
from datetime import datetime, timedelta

def utc_to_local(utc_dt):
    # get integer timestamp to avoid precision lost
    timestamp = calendar.timegm(utc_dt.timetuple())
    local_dt = datetime.fromtimestamp(timestamp)
    assert utc_dt.resolution >= timedelta(microseconds=1)
    return local_dt.replace(microsecond=utc_dt.microsecond)

사용하기 pytz(파이썬 2/3) :

import pytz

local_tz = pytz.timezone('Europe/Moscow') # use your local timezone name here
# NOTE: pytz.reference.LocalTimezone() would produce wrong result here

## You could use `tzlocal` module to get local timezone on Unix and Win32
# from tzlocal import get_localzone # $ pip install tzlocal

# # get local timezone    
# local_tz = get_localzone()

def utc_to_local(utc_dt):
    local_dt = utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
    return local_tz.normalize(local_dt) # .normalize might be unnecessary

def aslocaltimestr(utc_dt):
    return utc_to_local(utc_dt).strftime('%Y-%m-%d %H:%M:%S.%f %Z%z')

print(aslocaltimestr(datetime(2010,  6, 6, 17, 29, 7, 730000)))
print(aslocaltimestr(datetime(2010, 12, 6, 17, 29, 7, 730000)))
print(aslocaltimestr(datetime.utcnow()))

산출

파이썬 3.3
2010-06-06 21:29:07.730000 MSD+0400
2010-12-06 20:29:07.730000 MSK+0300
2012-11-08 14:19:50.093745 MSK+0400
파이썬 2
2010-06-06 21:29:07.730000 
2010-12-06 20:29:07.730000 
2012-11-08 14:19:50.093911 
피츠
2010-06-06 21:29:07.730000 MSD+0400
2010-12-06 20:29:07.730000 MSK+0300
2012-11-08 14:19:50.146917 MSK+0400

참고 : DST와 MSK 시간대의 최근 utc 오프셋 변경을 고려합니다.

비 피츠 솔루션이 Windows에서 작동하는지 여부를 모르겠습니다.


1
'정규화'는 무엇을합니까?
avi

4
@avi : 일반적으로 : pytz : 시간대 간 변환시 정규화가 필요한 이유는 무엇입니까? . 참고 : .normalize()소스 시간대 .astimezone()는 UTC 이므로 현재 구현에서는 필요하지 않습니다 .
jfs

1
TypeError: replace() takes no keyword argumentspytz 솔루션을 시도 할 때 얻습니다 .
Craig

@Craig는 답변의 출력이 보여주는 것처럼 코드가 그대로 작동합니다. TypeError로 이어지는 완전한 최소 코드 예제를 만들고 사용하는 Python, pytz 버전을 언급하고 별도의 스택 오버플로 질문으로 게시하십시오.
jfs 2016 년

Python 3.3+ 솔루션을위한 빠른 팁. 반대 방향으로 가려면 (UTC 기준) 다음과 같이 작동합니다. local_dt.replace(tzinfo=None).astimezone(tz=timezone.utc)
jasonrhaas

50

표준 라이브러리에는 시간대가 없으므로 표준 라이브러리만으로는 수행 할 수 없습니다. pytz 또는 dateutil 이 필요합니다 .

>>> from datetime import datetime
>>> now = datetime.utcnow()
>>> from dateutil import tz
>>> HERE = tz.tzlocal()
>>> UTC = tz.gettz('UTC')

The Conversion:
>>> gmt = now.replace(tzinfo=UTC)
>>> gmt.astimezone(HERE)
datetime.datetime(2010, 12, 30, 15, 51, 22, 114668, tzinfo=tzlocal())

또는 자신의 시간대를 구현하여 pytz 또는 dateutil없이 할 수 있습니다. 그러나 그것은 어리석은 일입니다.


고마워, 나는 완전한 해결책이 필요하다면 그것을 손에 쥐겠다. dateutil은 Python 3.1을 지원합니까 (Python 2.3 이상).
니트로 자크


pytz는 실제로 DST 전환을 더 잘 처리합니다.
Lennart Regebro

2
업데이트 : pytz와 dateutil은 현재 Python 3을 지원합니다.
Lennart Regebro

1
@JFSebastian : dateutil은 DST 전환 중에 발생하는 두 1:30 시간을 구분할 수 없습니다. 이 두 번을 구별 할 수 있어야하는 경우, 해결 방법은 pytz를 사용하여 처리 할 수 ​​있습니다.
Lennart Regebro 5

8

표준 라이브러리로는 할 수 없습니다. pytz 모듈을 사용하면 순진 / 인식 날짜 / 시간 객체를 다른 시간대로 변환 할 수 있습니다. Python 3을 사용하는 몇 가지 예를 살펴 보겠습니다.

클래스 메소드를 통해 생성 된 순진한 객체 utcnow()

순진한 개체를 다른 시간대 로 변환하려면 먼저 인식 할 수있는 날짜 / 시간 개체 로 변환해야 합니다. 순진한 datetime 객체를 인식 하는 datetime 객체로 replace변환하는 방법을 사용할 수 있습니다 . 그런 다음 인식 가능한 날짜 시간 객체를 다른 시간대 로 변환 하려면 메소드 를 사용할 수 있습니다 .astimezone

변수 pytz.all_timezones는 pytz 모듈에서 사용 가능한 모든 시간대 목록을 제공합니다.

import datetime,pytz

dtobj1=datetime.datetime.utcnow()   #utcnow class method
print(dtobj1)

dtobj3=dtobj1.replace(tzinfo=pytz.UTC) #replace method

dtobj_hongkong=dtobj3.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
print(dtobj_hongkong)

클래스 메소드를 통해 생성 된 순진한 객체 now()

때문에 now메소드가 리턴 현재 날짜와 시간, 그래서 당신은 날짜 개체 시간대 인식 먼저 확인해야합니다. 이 localize 함수는 순진한 날짜 / 시간 객체를 표준 시간대 인식 날짜 / 시간 객체로 변환 합니다. 그런 다음이 astimezone방법을 사용하여 다른 시간대로 변환 할 수 있습니다 .

dtobj2=datetime.datetime.now()

mytimezone=pytz.timezone("Europe/Vienna") #my current timezone
dtobj4=mytimezone.localize(dtobj2)        #localize function

dtobj_hongkong=dtobj4.astimezone(pytz.timezone("Asia/Hong_Kong")) #astimezone method
print(dtobj_hongkong)

6

나는 그것을 생각했다 : 에포크 이후 초 수를 계산 한 다음 time.localtime을 사용하여 로컬 timzeone으로 변환 한 다음 시간 구조를 다시 날짜 시간으로 변환합니다 ...

EPOCH_DATETIME = datetime.datetime(1970,1,1)
SECONDS_PER_DAY = 24*60*60

def utc_to_local_datetime( utc_datetime ):
    delta = utc_datetime - EPOCH_DATETIME
    utc_epoch = SECONDS_PER_DAY * delta.days + delta.seconds
    time_struct = time.localtime( utc_epoch )
    dt_args = time_struct[:6] + (delta.microseconds,)
    return datetime.datetime( *dt_args )

여름 / 겨울 DST를 올바르게 적용합니다.

>>> utc_to_local_datetime( datetime.datetime(2010, 6, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 6, 6, 19, 29, 7, 730000)
>>> utc_to_local_datetime( datetime.datetime(2010, 12, 6, 17, 29, 7, 730000) )
datetime.datetime(2010, 12, 6, 18, 29, 7, 730000)

1
어. 그러나 그것은 적어도 유닉스에서 작동해야합니다. Windows의 경우 변환 날짜 이후 일광 절약 규칙이 변경된 경우 올바르지 않을 수 있습니다. 라이브러리를 사용하고 싶지 않은 이유는 무엇입니까?
Lennart Regebro

utc / local 변환 만 필요하므로 그러한 라이브러리를 드래그하는 것은 과도하게 보입니다. 나는 응용 프로그램의 유일한 사용자이기 때문에 몇 가지 제한 사항으로 살 수 있습니다. 또한 작은 스크립트에서 작업하는 것보다 비용이 많이 드는 종속성 관련 문제 (Python 3 ?, Windows? 품질 지원)를 피하십시오.
니트로 자크

1
잘. 파이썬 3이 필요하다면 운이 좋지 않습니다. 그러나 그렇지 않으면 라이브러리를 사용하는 것보다 연구하고 자신의 솔루션을 만드는 것은 과잉입니다.
Lennart Regebro

1
주의 사항 @Lennart가 언급 한 +1 (공감대 상쇄 : stdlib 전용 솔루션을 찾는 것이 유효한 요구 사항 일 수 있음). 해당 dateutil이 Unix와 Windows에서 모두 실패 할 수 있습니다 . btw, utctotimestamp(utc_dt) -> (seconds, microseconds)명확성을 위해 코드에서 추출 할 수 있습니다. Python 2.6-3.x 구현
jfs

1
pytz (및 dateutil)는 얼마 전부터 Python 3에서 작동하므로 Python3 / Windows / Quality 문제는 더 이상 문제가되지 않습니다.
Lennart Regebro

6

Alexei의 의견을 바탕으로합니다. 이것은 DST에서도 작동합니다.

import time
import datetime

def utc_to_local(dt):
    if time.localtime().tm_isdst:
        return dt - datetime.timedelta(seconds = time.altzone)
    else:
        return dt - datetime.timedelta(seconds = time.timezone)

4

표준 Python 라이브러리에는 tzinfo구현 이 전혀 제공되지 않습니다 . 나는 항상 이것을 datetime 모듈의 놀라운 단점이라고 생각했습니다.

tzinfo 클래스에 대한 문서는 몇 가지 유용한 예제와 함께 않습니다. 섹션 끝에서 큰 코드 블록을 찾으십시오.


1
핵심 구현에 대한 나의 추측은 일부 국가에는 DST 기간을 결정하는 고정 규칙이 없으므로 시간대 데이터베이스를 정기적으로 업데이트해야하기 때문입니다. 내가 실수하지 않으면, 예를 들어 마지막 시간대 데이터베이스를 얻기 위해 예를 들어 JVM을 업데이트해야합니다 ...
Nitro Zark

@Nitro Zark, 적어도 UTC에는 하나가 있어야합니다. 이 os모듈은 운영 체제 기능에 따라 현지 시간으로 제공 할 수 있습니다.
Mark Ransom

1
3.2의 새로운 기능 목록을 확인하고 3.2의 UTC 시간대를 추가했습니다 ( docs.python.org/dev/whatsnew/3.2.html#datetime ). 현지 시간대가없는 것 같습니다 ...
Nitro Zark

2

Python 3.9는 zoneinfo모듈을 추가하여 다음과 같이 수행 할 수 있습니다 (stdlib 만 해당).

from zoneinfo import ZoneInfo
from datetime import datetime

utc_unaware = datetime(2020, 10, 31, 12)  # loaded from database
utc_aware = utc_unaware.replace(tzinfo=ZoneInfo('UTC'))  # make aware
local_aware = utc_aware.astimezone(ZoneInfo('localtime'))  # convert

중부 유럽 표준시 (UTC)보다 1-2 시간 빠릅니다 local_aware.

datetime.datetime(2020, 10, 31, 13, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='localtime'))

str:

2020-10-31 13:00:00+01:00

Windows 에는 시스템 시간대 데이터베이스가 없으므로 여기에 추가 패키지가 필요합니다.

pip install tzdata  

Python 3.6 ~ 3.8 에서 사용할 수있는 백 포트가 있습니다 .

sudo pip install backports.zoneinfo

그때:

from backports.zoneinfo import ZoneInfo

당신은 zoneinfo여기에 필요하지 않습니다 -jfs 의 답변 의 첫 번째 부분 (Python3.3 + 부분) ;-) 참조
MrFuppes

@MrFuppes ZoneInfo('localtime')보다 명확 하다고 생각합니다 tz=None(결국 tz=None시간대를 제거하거나 현지 시간보다 UTC를 반환 할 것으로 예상 할 수 있음 ).
xjcl

@MrFuppes Plus 질문에는 OP에 웹 사이트가 있고 현지 시간으로 사용자 타임 스탬프를 표시하려는 것이 포함될 수 있습니다. 이를 위해서는 현지 시간이 아닌 사용자의 명시 적 시간대로 변환해야합니다.
xjcl

0

파이썬 2와 3에서 작동하는 간단한 (아마도 결함이있는) 방법

import time
import datetime

def utc_to_local(dt):
    return dt - datetime.timedelta(seconds = time.timezone)

장점은 역함수를 작성하는 것이 쉽지 않다는 것입니다.


1
time.timezone일광 절약 시간제를 고려하지 않으므로 잘못된 결과 가 나타납니다.
guyarad

0

내가 찾은 가장 쉬운 방법은 시간이 곳의 오프셋을 얻을 수 있습니다 당신이 있습니다, 다음 시간에서 해당을 뺍니다.

def format_time(ts,offset):
    if not ts.hour >= offset:
        ts = ts.replace(day=ts.day-1)
        ts = ts.replace(hour=ts.hour-offset)
    else:
        ts = ts.replace(hour=ts.hour-offset)
    return ts

이것은 Python 3.5.2에서 작동합니다.


0

날짜 시간 형식으로 시간대를 변경하는 또 다른 방법은 다음과 같습니다 (나는이 에너지를 낭비했지만이 페이지를 보지 못했기 때문에 어떻게 알지 못했습니다). 그리고 초. 내 프로젝트에 필요하지 않습니다.

def change_time_zone(year, month, day, hour):
      hour = hour + 7 #<-- difference
      if hour >= 24:
        difference = hour - 24
        hour = difference
        day += 1
        long_months = [1, 3, 5, 7, 8, 10, 12]
        short_months = [4, 6, 9, 11]
        if month in short_months:
          if day >= 30:
            day = 1
            month += 1
            if month > 12:
              year += 1
        elif month in long_months:
          if day >= 31:
            day = 1
            month += 1
            if month > 12:
              year += 1
        elif month == 2:
          if not year%4==0:
            if day >= 29:
              day = 1
              month += 1
              if month > 12:
                year += 1
          else:
            if day >= 28:
              day = 1
              month += 1
              if month > 12:
                year += 1
      return datetime(int(year), int(month), int(day), int(hour), 00)

시간대를 전환하려면 시간대를 사용하십시오. 시간대 사이의 시간 단위 오프셋 만 있으면됩니다. 날짜 / 시간 객체의 6 개 요소 모두에 경계를 두지 않아도됩니다. timedelta는 윤년, 윤년 등을 쉽게 처리합니다. 'datetime import timedelta에서'여야합니다. 그런 다음 오프셋이 시간 단위의 변수 인 경우 : timeout = timein + timedelta (hours = offset), 여기서 timein 및 timeout은 datetime 객체입니다. 예를 들어 timein + timedelta (hours = -8)은 GMT에서 PST로 변환됩니다.
Karl Rudnick '12

0

이것은 끔찍한 방법이지만 정의를 만드는 것을 피합니다. 기본 Python3 라이브러리를 고수해야합니다.

# Adjust from UST to Eastern Standard Time (dynamic)
# df.my_localtime should already be in datetime format, so just in case
df['my_localtime'] = pd.to_datetime.df['my_localtime']

df['my_localtime'] = df['my_localtime'].dt.tz_localize('UTC').dt.tz_convert('America/New_York').astype(str)
df['my_localtime'] = pd.to_datetime(df.my_localtime.str[:-6])

이것은 흥미롭고이 방법을 사용하려고하지만 stdlib 만 사용하지는 않습니다. 그것은 판다를 사용하여 변환을 수행하고 있습니다. pandas.pydata.org/pandas-docs/version/0.25/reference/api/…
Tim Hughes

-3

시간대를 전환하려면 시간대를 사용하십시오. 시간대 사이의 시간 단위 오프셋 만 있으면됩니다. 날짜 / 시간 객체의 6 개 요소 모두에 경계를 두지 않아도됩니다. timedelta는 윤년, 윤년 등을 쉽게 처리합니다. 먼저해야합니다

from datetime import datetime, timedelta

그런 다음 offset시간대 델타가 시간 인 경우 :

timeout = timein + timedelta(hours = offset)

여기서 timein 및 timeout은 datetime 객체입니다. 예 :

timein + timedelta(hours = -8)

GMT에서 PST로 변환합니다.

그래서 어떻게 결정 offset합니까? 여기에 다른 함수가 잘 수행하는 시간대 "인식"인 datetime 객체를 사용하지 않고 변환 할 수있는 간단한 기능이 있습니다. 약간 수동이지만 때로는 선명도가 가장 좋습니다.

def change_timezone(timein, timezone, timezone_out):
    '''
    changes timezone between predefined timezone offsets to GMT
    timein - datetime object
    timezone - 'PST', 'PDT', 'GMT' (can add more as needed)
    timezone_out - 'PST', 'PDT', 'GMT' (can add more as needed)
    ''' 
    # simple table lookup        
    tz_offset =  {'PST': {'GMT': 8, 'PDT': 1, 'PST': 0}, \
                  'GMT': {'PST': -8, 'PDT': -7, 'GMT': 0}, \
                  'PDT': {'GMT': 7, 'PST': -1, 'PDT': 0}}
    try:
        offset = tz_offset[timezone][timezone_out]
    except:
        msg = 'Input timezone=' + timezone + ' OR output time zone=' + \
            timezone_out + ' not recognized'
        raise DateTimeError(msg)

    return timein + timedelta(hours = offset)

많은 답변을보고 생각할 수있는 가장 엄격한 코드로 놀아 본 후 (현재) 시간이 중요하고 혼합 시간대를 고려해야하는 모든 응용 프로그램이 모든 datetime 객체를 만들기 위해 실제로 노력해야하는 것이 가장 좋습니다. "인식". 그렇다면 가장 간단한 대답은 다음과 같습니다.

timeout = timein.astimezone(pytz.timezone("GMT"))

예를 들어 GMT로 변환합니다. 물론 로컬 또는 다른 원하는 시간대로 변환하려면 pytz가 이해하는 적절한 시간대 문자열을 사용하십시오 (pytz.all_timezones에서). 그런 다음 일광 절약 시간도 고려됩니다.


1
이것은 좋은 생각이 아닙니다. DST는 전 세계에 대해 동일한 날짜로 이동하지 않습니다. datetime 함수를 사용하여이를 수행하십시오.
Gabe

@gabe-미국 시간대 만 다루는 사람에게도 적합하지만이 테이블은 좋지 않다는 것을 이해하십시오. 마지막에 말했듯이 가장 좋은 방법은 항상 datetime 객체를 "인식"하여 datetime 함수를 쉽게 사용할 수 있도록하는 것입니다.
Karl Rudnick
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.