programing

표준 시간대 인식 날짜/시간 개체를 만드는 방법

kingscode 2022. 10. 29. 11:56
반응형

표준 시간대 인식 날짜/시간 개체를 만드는 방법

해야 할 일

타임존 비대응 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
>>>

실제로 변환을 시도하고 있기 때문에 실패한 것은 그리 놀라운 일이 아닙니다.치환(How do I get a value of datetime)이 더 나은 선택인 것 같습니다.python에서는 timezone을 인식하고 있습니까?:

>>> 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을 사용하고 있습니다). 하지만 그것은 매우 애매한 것 같습니다.

또한 Python 2.6과 Python 2.7 모두에서 동일한 결과를 얻었습니다.

맥락

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

일반적으로 naigive datetime 타임존을 인식하려면 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'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE: 'CHANGE:

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

가 있다.replace 날짜/시간을 이/은 변경되지 .unaware

다음 예에서는 모두 외부 모듈을 사용하지만 다음 SO 답변에서도 나타나듯이 datetime 모듈만 사용해도 동일한 결과를 얻을 수 있습니다.

from datetime import datetime, timezone

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

print(dt.isoformat())
# '2017-01-12T22:11:31+00:00'

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

메모: 이것을 python3 및 python2 와 함께 사용하는 경우는, 타임 존 Import에도 사용할 수 있습니다(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()

이 Python 2 스크립트는 2011년에 작성했지만 Python 3에서 동작하는지 확인하지 못했습니다.

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)

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

from django.utils import timezone

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

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

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'

위키피디아 사용 가능한 시간대 목록


Windows 에는 시스템 타임 존 데이터베이스가 없기 때문에, 여기에서는 추가 패키지가 필요합니다.

pip install tzdata  

를 사용할 수 있는 백포트가 있습니다.zoneinfoPython 3.6에서 3.8:

pip install backports.zoneinfo

그 후, 다음과 같이 입력합니다.

from backports.zoneinfo import ZoneInfo

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

이름만 입력하면 replace()가 적용되어 적절한 datetime 인식 객체를 생성할 수 있습니다.이것은 사실이 아니다.

replace( tzinfo=...) )의 동작은 랜덤인 것 같습니다.그러므로 그것은 쓸모가 없다.이것을 사용하지 마세요!

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

localdatetime_aware = tz.localize(datetime_nonaware)

또는 보다 완전한 예를 제시하겠습니다.

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

그럼 현재 현지 시각의 타임존 대응 datetime 값이 표시됩니다.

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

를 사용하여 및 을 사용하는 타임존을 가져옵니다.

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먼저 변환합니다.datetimeUTC에 대한 오브젝트 후 타임존에 대한 콜과 같은datetime.replace원래 시간대 정보를 사용하여None.

이것은 @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()tz 인수에 문자열과 타임존 오브젝트를 모두 받아들이고 타임존이 지정되지 않은 경우 기본 UTC가 됩니다.

표준시 대응 datetime을 원하는 사용자용

import datetime

datetime.datetime(2019, 12, 7, tzinfo=datetime.timezone.utc)

python 3.9 stdlib로 시작하는 UTC 이외의 타임존을 가진 datetime을 원하는 사용자용

import datetime
from zoneinfo import ZoneInfo

datetime.datetime(2019, 12, 7, tzinfo=ZoneInfo("America/Los_Angeles")) 

또 다른 방법으로는datetime순진하지 않은 객체:

>>> from datetime import datetime, timezone
>>> datetime.now(timezone.utc)
datetime.datetime(2021, 5, 1, 22, 51, 16, 219942, tzinfo=datetime.timezone.utc)

Python은 매우 처음이고 저도 같은 문제를 겪었습니다.이 솔루션은 매우 심플하고, 나에게 있어서 정상적으로 동작합니다(Python 3.6).

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

다음은 코드의 변경을 최소화하는 간단한 솔루션입니다.

from datetime import datetime
import pytz

start_utc = datetime.utcnow()
print ("Time (UTC): %s" % start_utc.strftime("%d-%m-%Y %H:%M:%S"))

시간(UTC): 09-01-2021 03:49:03

tz = pytz.timezone('Africa/Cairo')
start_tz = datetime.now().astimezone(tz)
print ("Time (RSA): %s" % start_tz.strftime("%d-%m-%Y %H:%M:%S"))

시간(RSA): 09-01-2021 05:49:03

unutbu의 답변 형식으로, 이런 것을 다루는 보다 직관적인 구문을 가진 유틸리티 모듈을 만들었습니다.pip과 함께 설치할 수 있습니다.

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')

시간대 간 변경

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

특히 Unix 타임스탬프일 경우 팬더를 사용하는 매우 간단한 솔루션이 있습니다.

import pandas as pd

unix_timestamp = 1513393355
pst_tz = pd.Timestamp(unix_timestamp, unit='s', tz='US/Pacific')
utc_tz = pd.Timestamp(unix_timestamp, unit='s', tz='UTC')

언급URL : https://stackoverflow.com/questions/7065164/how-to-make-a-timezone-aware-datetime-object

반응형