파이썬에서 인식하지 못하는 날짜 시간 시간대를 인식시키는 방법


506

내가해야 할 일

시간대를 인식하지 못하는 datetime 객체가 있는데 다른 시간대를 인식하는 datetime 객체와 비교하려면 시간대를 추가해야합니다. 이 하나의 레거시 사례에 대해 전체 응용 프로그램을 표준 시간대로 변환하고 싶지 않습니다.

내가 시도한 것

먼저, 문제를 보여주기 위해 :

Python 2.6.1 (r261:67515, Jun 24 2010, 21:47:49) 
[GCC 4.2.1 (Apple Inc. build 5646)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import datetime
>>> import pytz
>>> unaware = datetime.datetime(2011,8,15,8,15,12,0)
>>> unaware
datetime.datetime(2011, 8, 15, 8, 15, 12)
>>> aware = datetime.datetime(2011,8,15,8,15,12,0,pytz.UTC)
>>> aware
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> aware == unaware
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes

먼저 시간대로 시도했습니다.

>>> unaware.astimezone(pytz.UTC)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: astimezone() cannot be applied to a naive datetime
>>>

실제로 변환을 시도하고 있기 때문에 이것이 실패한 것은 놀라운 일이 아닙니다. 바꾸기는 더 나은 선택처럼 보였습니다 ( Python에 따르면 : "timezone aware"인 datetime.today () 값을 얻는 방법은 무엇입니까? ) :

>>> unaware.replace(tzinfo=pytz.UTC)
datetime.datetime(2011, 8, 15, 8, 15, 12, tzinfo=<UTC>)
>>> unaware == aware
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't compare offset-naive and offset-aware datetimes
>>> 

그러나 보시다시피 replace는 tzinfo를 설정하는 것으로 보이지만 객체를 인식하지 못합니다. 입력 문자열을 구문 분석하기 전에 시간대를 갖도록 의사 결정을 할 준비가되어 있습니다 (필요한 경우 구문 분석에 dateutil을 사용하고 있습니다).

또한 파이썬 2.6과 파이썬 2.7 에서이 결과를 시도했습니다.

문맥

일부 데이터 파일에 대한 파서를 작성 중입니다. 날짜 문자열에 시간대 표시 기가없는 곳에서 지원 해야하는 오래된 형식이 있습니다. 이미 데이터 소스를 수정했지만 여전히 레거시 데이터 형식을 지원해야합니다. 레거시 데이터의 일회성 변환은 다양한 비즈니스 BS 이유로 인해 옵션이 아닙니다. 일반적으로 기본 시간대를 하드 코딩하는 아이디어가 마음에 들지 않지만이 경우 가장 좋은 옵션 인 것 같습니다. 문제가되는 모든 레거시 데이터가 UTC로되어 있다는 확신을 가지고 있으므로이 경우 기본 설정의 위험을 감수 할 준비가되어 있습니다.


1
unaware.replace()객체를 제자리 None에서 수정하면 반환 됩니다 unaware. REPL은 여기에 .replace()새로운 datetime객체 를 반환 한다는 것을 보여줍니다 .
jfs

3
내가 여기 왔을 때 필요한 것 :import datetime; datetime.datetime.now(datetime.timezone.utc)
Martin Thoma

1
@MartinThoma 나는 이름을 사용하는 것이 tz더 읽을 수 ARG를 :datetime.datetime.now(tz=datetime.timezone.utc)
아큐 메 너스

답변:


594

일반적으로 순진한 날짜 시간 시간대를 인식하려면 localize 메소드를 사용하십시오 .

import datetime
import pytz

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
aware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0, pytz.UTC)

now_aware = pytz.utc.localize(unaware)
assert aware == now_aware

UTC 시간대의 경우 localize처리 할 일광 절약 시간제 계산 이 없으므로 실제로 사용할 필요 는 없습니다.

now_aware = unaware.replace(tzinfo=pytz.UTC)

공장. ( .replace새 날짜 시간을 반환하며 수정하지 않습니다 unaware.)


10
글쎄, 나는 바보 같은 느낌. 바꾸기는 새로운 날짜 시간을 반환합니다. 그것은 문서에도 거기에 있다고 말하고 완전히 그것을 놓쳤습니다. 고마워, 바로 내가 찾던 것입니다.
Mark Tozzi

2
"바꾸기는 새로운 날짜 시간을 반환합니다." 네. REPL이 제공하는 힌트는 반환 값을 표시한다는 것입니다. :)
Karl Knechtel-

덕분에 dt_aware에서 dt_unware = datetime.datetime (* (dt_aware.timetuple () [: 6]))을 인식하지 못했습니다.
Sérgio

4
시간대가 직접 생성자를 사용하지 않는 다음 UTC가 아닌 경우 : aware = datetime(..., tz)사용 .localize()대신.
jfs

1
현지 시간이 모호 할 수 있음을 언급 할 가치가 있습니다. tz.localize(..., is_dst=None)그것이 아니라고 주장한다.
jfs

166

이 모든 예제는 외부 모듈을 사용하지만 이 SO 답변에 제시 된 것처럼 datetime 모듈 만 사용하여 동일한 결과를 얻을 수 있습니다 .

from datetime import datetime
from datetime import timezone

dt = datetime.now()
dt.replace(tzinfo=timezone.utc)

print(dt.replace(tzinfo=timezone.utc).isoformat())
'2017-01-12T22:11:31+00:00'

의존성이 적고 pytz 문제가 없습니다.

참고 : 이것을 python3 및 python2와 함께 사용하려면 시간대 가져 오기 (UTC 용 하드 코드)에도 사용할 수 있습니다.

try:
    from datetime import timezone
    utc = timezone.utc
except ImportError:
    #Hi there python2 user
    class UTC(tzinfo):
        def utcoffset(self, dt):
            return timedelta(0)
        def tzname(self, dt):
            return "UTC"
        def dst(self, dt):
            return timedelta(0)
    utc = UTC()

10
pytz문제 를 예방하는 데 아주 좋은 대답입니다 . pytz내 원격 서버에서 실제로 다루고 싶지 않았습니다 :)
Tregoreg

7
참고 from datetime import timezonepy3하지만 py2.7에서 작동합니다.
7yl4r

11
dt.replace(tzinfo=timezone.utc)새로운 날짜 / 시간 을 반환하지만 해당 위치 는 수정되지 않습니다 dt. (나는 이것을 보여주기 위해 편집 할 것이다).
Blairg23

2
timezone.utc를 사용하는 대신 어떻게 다른 시간대를 문자열로 제공 할 수 있습니까 (예 : "America / Chicago")?
bumpkin

2
@bumpkin 더 늦게보다 늦게, 나는 생각한다 :tz = pytz.timezone('America/Chicago')
Florian

82

dt_aware에서 dt_unaware로 사용했습니다.

dt_unaware = dt_aware.replace(tzinfo=None)

dt_unware에서 dt_aware로

from pytz import timezone
localtz = timezone('Europe/Lisbon')
dt_aware = localtz.localize(dt_unware)

그러나 전에 대답하는 것도 좋은 해결책입니다.


2
당신이 사용할 수있는 localtz.localize(dt_unware, is_dst=None)경우 예외를 발생하기 위해 dt_unware존재하지 않는 또는 모호한 현지 시간 (메모를 나타냅니다 답변의 이전 버전에서 그런 문제가 없었다 localtzUTC 더 DST 전환이 없기 때문에 UTC이었다
JFS를

@JF Sebastian, 첫 번째 댓글 적용
Sérgio

1
전환의 두 가지 방향을 보여 주셔서 감사합니다.
Christian Long

42

Django 에서이 문장을 사용하여 인식하지 못하는 시간을 인식으로 변환합니다.

from django.utils import timezone

dt_aware = timezone.make_aware(dt_unaware, timezone.get_current_timezone())

2
나는이 솔루션 (+1)을 좋아하지만 장고에 의존합니다. 이것은 그들이 찾고있는 것이 아닙니다 (-1). =)
mkoistinen

3
실제로 두 번째 주장은 아닙니다. 기본 인수 (없음) 로컬 시간대가 암시 적으로 사용되는 의미합니다. DST와 동일 (세번째 인수
Oli

14

이전 답변에 동의하며 UTC로 시작해도 괜찮습니다. 그러나 UTC가 아닌 현지 시간대 가있는 날짜 시간을 가진 tz 인식 값으로 작업하는 것이 일반적인 시나리오라고 생각합니다 .

그냥 이름 만 사용한다면, 아마도 replace ()가 적용되고 올바른 날짜 / 시간 인식 객체를 생성 할 것입니다. 그렇지 않다.

replace (tzinfo = ...)는 동작이 무작위 인 것 같습니다 . 따라서 쓸모가 없습니다. 이것을 사용하지 마십시오!

localize는 올바른 기능입니다. 예:

localdatetime_aware = tz.localize(datetime_nonaware)

또는 더 완전한 예 :

import pytz
from datetime import datetime
pytz.timezone('Australia/Melbourne').localize(datetime.now())

현재 현지 시간의 시간대를 인식하는 시간대를 제공합니다.

datetime.datetime(2017, 11, 3, 7, 44, 51, 908574, tzinfo=<DstTzInfo 'Australia/Melbourne' AEDT+11:00:00 DST>)

3
replace(tzinfo=...)UTC가 아닌 다른 시간대 에서 시도하면 더 많은 투표가 필요 합니다. 내가 가지고 -07:53대신 -08:00예를 들어. 참조 stackoverflow.com/a/13994611/1224827
Blairg23

replace(tzinfo=...)예기치 않은 행동을 하는 재현 가능한 예를 들어 줄 수 있습니까 ?
xjcl

11

사용 및 dateutil.tz.tzlocal()시간대를 얻기 위해 사용datetime.datetime.now()datetime.datetime.astimezone() .

from datetime import datetime
from dateutil import tz

unlocalisedDatetime = datetime.now()

localisedDatetime1 = datetime.now(tz = tz.tzlocal())
localisedDatetime2 = datetime(2017, 6, 24, 12, 24, 36, tz.tzlocal())
localisedDatetime3 = unlocalisedDatetime.astimezone(tz = tz.tzlocal())
localisedDatetime4 = unlocalisedDatetime.replace(tzinfo = tz.tzlocal())

참고 datetime.astimezone먼저 변환됩니다 datetime호출과 동일한 시간대로 다음 UTC에 개체를 datetime.replace원래 시간대 정보의 존재와 함께 None.


1
UTC로 만들고 싶다면 :.replace(tzinfo=dateutil.tz.UTC)
Martin Thoma

2
하나의 수입은 적고 단지 :.replace(tzinfo=datetime.timezone.utc)
kubanczyk

9

이것은 @ Sérgio와 @unutbu의 답변을 체계화 합니다 . pytz.timezone개체 또는 IANA 표준 시간대 문자열 과 함께 "작동" 합니다.

def make_tz_aware(dt, tz='UTC', is_dst=None):
    """Add timezone information to a datetime object, only if it is naive."""
    tz = dt.tzinfo or tz
    try:
        tz = pytz.timezone(tz)
    except AttributeError:
        pass
    return tz.localize(dt, is_dst=is_dst) 

이것은 어떤 것 같아 datetime.localize()(또는 .inform()또는 .awarify()어떤 시간대가 지정되지 않은 경우 수행 UTC에 TZ 인수 및 기본 모두 문자열과 시간대 객체를 받아 들여야한다).


1
감사합니다. 이렇게하면 시스템이 먼저 현지 시간이라고 가정하고 값을 다시 계산하지 않고도 원시 날짜 시간 개체를 "UTC"로 "브랜드"할 수있었습니다.
Nikhil VJ

2

Python 3.9는 zoneinfo모듈을 추가 하므로 표준 라이브러리 만 필요합니다!

from zoneinfo import ZoneInfo
from datetime import datetime
unaware = datetime(2020, 10, 31, 12)

시간대를 첨부하십시오.

>>> unaware.replace(tzinfo=ZoneInfo('Asia/Tokyo'))
datetime.datetime(2020, 10, 31, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='Asia/Tokyo'))
>>> str(_)
'2020-10-31 12:00:00+09:00'

시스템의 현지 시간대를 연결하십시오.

>>> unaware.replace(tzinfo=ZoneInfo('localtime'))
datetime.datetime(2020, 10, 31, 12, 0, tzinfo=zoneinfo.ZoneInfo(key='localtime'))
>>> str(_)
'2020-10-31 12:00:00+01:00'

결과적으로 다른 시간대로 올바르게 변환됩니다.

>>> unaware.replace(tzinfo=ZoneInfo('localtime')).astimezone(ZoneInfo('Asia/Tokyo'))
datetime.datetime(2020, 10, 31, 20, 0, tzinfo=backports.zoneinfo.ZoneInfo(key='Asia/Tokyo'))
>>> str(_)
'2020-10-31 20:00:00+09:00'

사용 가능한 시간대의 위키 백과 목록


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

sudo pip install backports.zoneinfo

그때:

from backports.zoneinfo import ZoneInfo

0

unutbu의 답변 형식으로; 더 직관적 인 구문으로 이와 같은 것을 처리하는 유틸리티 모듈을 만들었습니다. 핍과 함께 ​​설치할 수 있습니다.

import datetime
import saturn

unaware = datetime.datetime(2011, 8, 15, 8, 15, 12, 0)
now_aware = saturn.fix_naive(unaware)

now_aware_madrid = saturn.fix_naive(unaware, 'Europe/Madrid')

0

시간대를 인식하여 날짜 시간을 인식하려는 사람들을 위해

import datetime
import pytz

datetime.datetime(2019, 12, 7, tzinfo=pytz.UTC)

0

파이썬에 익숙하지 않아서 같은 문제가 발생했습니다. 이 솔루션은 매우 간단하고 나를 위해 잘 작동합니다 (Python 3.6).

unaware=parser.parse("2020-05-01 0:00:00")
aware=unaware.replace(tzinfo=tz.tzlocal()).astimezone(tz.tzlocal())

0

시간대 간 변경

import pytz
from datetime import datetime

other_tz = pytz.timezone('Europe/Madrid')

# From random aware datetime...
aware_datetime = datetime.utcnow().astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00

# 1. Change aware datetime to UTC and remove tzinfo to obtain an unaware datetime
unaware_datetime = aware_datetime.astimezone(pytz.UTC).replace(tzinfo=None)
>> 2020-05-21 06:28:26.984948

# 2. Set tzinfo to UTC directly on an unaware datetime to obtain an utc aware datetime
aware_datetime_utc = unaware_datetime.replace(tzinfo=pytz.UTC)
>> 2020-05-21 06:28:26.984948+00:00

# 3. Convert the aware utc datetime into another timezone
reconverted_aware_datetime = aware_datetime_utc.astimezone(other_tz)
>> 2020-05-21 08:28:26.984948+02:00

# Initial Aware Datetime and Reconverted Aware Datetime are equal
print(aware_datetime1 == aware_datetime2)
>> True
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.