UTC 날짜 / 시간 문자열을 현지 날짜 / 시간으로 변환


206

UTC와의 시간을 변환 할 필요가 없었습니다. 최근에 내 앱을 표준 시간대로 인식하라는 요청을 받았으며 서클에서 나 자신을 실행하고 있습니다. 현지 시간을 UTC로 변환하는 데 대한 많은 정보가 있습니다. 이것은 상당히 초등 한 것으로 나타났습니다 (아마도 잘못하고 있습니다) .UTC 시간을 최종 사용자 시간대로 쉽게 변환하는 방법에 대한 정보를 찾을 수 없습니다.

간단히 말해서 안드로이드 앱은 나에게 (appengine 앱) 데이터를 보내며 그 데이터 내에서 타임 스탬프입니다. 해당 타임 스탬프를 utc 시간으로 저장하려면 다음을 사용하십시오.

datetime.utcfromtimestamp(timestamp)

작동하는 것 같습니다. 내 앱이 데이터를 저장하면 5 시간 앞서 저장됩니다 (EST -5입니다)

데이터는 appengine의 BigTable에 저장되고 검색되면 다음과 같은 문자열로 나타납니다.

"2011-01-21 02:37:21"

사용자가 올바른 시간대에서이 문자열을 DateTime으로 어떻게 변환합니까?

또한 사용자 시간대 정보에 권장되는 스토리지는 무엇입니까? (일반적으로 tz 정보 (예 : "-5 : 00"또는 "EST"등)를 저장하는 방법은 무엇입니까?) 첫 번째 질문에 대한 답변에 두 번째 질문에 대한 매개 변수가 포함되어있을 것입니다.



이 답변 은 간단한 방법으로이 문제를 해결하는 방법을 보여줍니다.
juan

답변:


402

자신의 tzinfo객체 를 제공하지 않으려면 python-dateutil 라이브러리를 확인하십시오 . 다소 정식 이름으로 시간대 규칙을 참조 할 수 tzinfo있도록 zoneinfo (Olson) 데이터베이스 위에 구현을 제공합니다 .

from datetime import datetime
from dateutil import tz

# METHOD 1: Hardcode zones:
from_zone = tz.gettz('UTC')
to_zone = tz.gettz('America/New_York')

# METHOD 2: Auto-detect zones:
from_zone = tz.tzutc()
to_zone = tz.tzlocal()

# utc = datetime.utcnow()
utc = datetime.strptime('2011-01-21 02:37:21', '%Y-%m-%d %H:%M:%S')

# Tell the datetime object that it's in UTC time zone since 
# datetime objects are 'naive' by default
utc = utc.replace(tzinfo=from_zone)

# Convert time zone
central = utc.astimezone(to_zone)

strptime사용법 을 보여주기 위해 확장 된 예제 편집

더 나은 진입 점 방법을 표시하기 위해 2 개의 고정 API 사용량 편집

시간대에 대한 3 가지 자동 감지 방법 편집 (야린)


1
내 이전의 코멘트에, 나는 가져올 수 있었다 dateutil.tz사용 tz.tzutc()tz.tzlocal()시간대가 내가 찾던 개체로. 시스템의 표준 시간대 데이터베이스가 양호한 것 같습니다 (체크인 됨 /usr/share/zoneinfo). 무슨 일이 있었는지 잘 모르겠습니다.
벤 크리거

1
@ Benjamin 당신은 올바른 길을 가고 있습니다. tz모듈이 라이브러리에 사용되는 정확한 진입 점입니다. 이것을 반영하여 답변을 업데이트했습니다. dateutil.zoneinfo내가 이전에 표시 된 모듈은 내부적으로 사용 tz이 DB은 zoneinfo 시스템의를 찾을 수없는 경우 가을에 다시 같은 모듈. 라이브러리를 살펴보면 패키지에 시스템의 DB를 찾을 수없는 경우 사용하는 zoneinfo DB tarball이 있음을 알 수 있습니다. 예전 예제는 그 DB를 직접 치기 위해 노력했지만 개인 DB를로드하는 데 문제가 있다고 생각합니다 (파이썬 경로에 있지 않습니까?)
Joe Holloway


1
@JFSebastian 이것은 # 225
Rohmer

2
@briankip 응용 프로그램이 얼마나 정교해야하는지에 달려 있지만 일반적인 응용 프로그램에서는 문제가 있습니다. 우선 어떤 시간대가 DST를 따르고 다른 시간대를 따르지 않기 때문에 추가 / 빼기 시간은 변경 될 수 있습니다. 둘째, 시간대 규칙은 시간이 지남에 따라 임의로 변경되므로 과거 날짜 / 시간으로 작업하는 경우 현재 시간이 아닌 해당 시점에 유효한 규칙을 적용해야합니다. 그렇기 때문에 뒤에서 Olson TZ 데이터베이스를 활용하는 API를 사용하는 것이 가장 좋습니다.
Joe Holloway

44

외부 라이브러리에 의존하지 않는 탄력적 인 방법은 다음과 같습니다.

from datetime import datetime
import time

def datetime_from_utc_to_local(utc_datetime):
    now_timestamp = time.time()
    offset = datetime.fromtimestamp(now_timestamp) - datetime.utcfromtimestamp(now_timestamp)
    return utc_datetime + offset

이것은 DelboyJay의 예제에서 타이밍 문제를 피합니다. 그리고 Erik van Oosten의 개정에서 더 적은 타이밍 문제.

흥미로운 각주로서 위에서 계산 된 표준 시간대 오프셋은 일광 절약 규칙 변경으로 인해 다음과 같은 겉보기에 해당되는 표현과 다를 수 있습니다.

offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO!

업데이트 : 이 스 니펫은 현재 시간의 UTC 오프셋을 사용하는 취약점이 있으며 입력 날짜 시간의 UTC 오프셋과 다를 수 있습니다. 다른 솔루션에 대해서는이 답변에 대한 의견을 참조하십시오.

다른 시간을 돌아 다니려면 지나간 시간부터 신기원 시간을 잡으십시오. 다음은 내가하는 일입니다.

def utc2local (utc):
    epoch = time.mktime(utc.timetuple())
    offset = datetime.fromtimestamp (epoch) - datetime.utcfromtimestamp (epoch)
    return utc + offset

이것은 잘 작동하며 시간과 날짜 시간 외에는 아무것도 필요하지 않습니다.
Mike_K

6
@ Mike_K : 맞지 않습니다. 다른 이유로 과거에 다른 UTC 오프셋을 가진 DST 또는 시간대를 지원하지 않습니다. pytz-like db가없는 완전한 지원 은 불가능합니다 (PEP-431 참조). Linux, OS X와 ​​같이 이미 역사적인 시간대 DB를 가진 시스템에서 이러한 경우 작동하는 stdlib 전용 솔루션을 작성할 수 있지만 내 대답을 참조하십시오 .
jfs

@ JFSebastian :이 코드는 일반적으로 작동하지 않지만 OS X 및 Linux에서 작동한다고 말합니다. 이 코드가 Windows에서 작동하지 않습니까?
David Foster

2
@DavidFoster : Linux 및 OS X에서도 코드가 실패 할 수 있습니다. 귀하와 내 stdlib 전용 솔루션 의 차이점은 귀하의 시간에 utc 오프셋과 다를 수있는 현재 오프셋을 사용한다는 것 utc_datetime입니다.
jfs

1
잘 했어 그것은 매우 미묘한 차이입니다. UTC 오프셋도 시간이 지남에 따라 변경 될 수 있습니다. 한숨
David Foster

23

tzinfo 객체 에 대한 날짜 및 시간 설명서를 참조하십시오 . 자신을 지원하려는 시간대를 구현해야합니다. 문서 하단에있는 예입니다.

다음은 간단한 예입니다.

from datetime import datetime,tzinfo,timedelta

class Zone(tzinfo):
    def __init__(self,offset,isdst,name):
        self.offset = offset
        self.isdst = isdst
        self.name = name
    def utcoffset(self, dt):
        return timedelta(hours=self.offset) + self.dst(dt)
    def dst(self, dt):
            return timedelta(hours=1) if self.isdst else timedelta(0)
    def tzname(self,dt):
         return self.name

GMT = Zone(0,False,'GMT')
EST = Zone(-5,False,'EST')

print datetime.utcnow().strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(GMT).strftime('%m/%d/%Y %H:%M:%S %Z')
print datetime.now(EST).strftime('%m/%d/%Y %H:%M:%S %Z')

t = datetime.strptime('2011-01-21 02:37:21','%Y-%m-%d %H:%M:%S')
t = t.replace(tzinfo=GMT)
print t
print t.astimezone(EST)

산출

01/22/2011 21:52:09 
01/22/2011 21:52:09 GMT
01/22/2011 16:52:09 EST
2011-01-21 02:37:21+00:00
2011-01-20 21:37:21-05:00a

받아 줘서 고마워! 특정 예제 시간을 번역하기 위해 약간 업데이트했습니다. 시간을 파싱하면 문서에서 "순진한"시간을 생성합니다. 사용은 replaceGMT로 시간대를 설정하고이 시간대 "인식"다음 사용하도록하는 astimezone다른 시간대로 변환 할 수 있습니다.
Mark Tolonen

Joe의 답변을 바꾸어 죄송합니다. 기술적으로 당신의 대답은 원시 파이썬 (알아두면 좋은)으로 그것을 수행하는 방법을 정확하게 설명하지만, 그가 제안한 라이브러리는 훨씬 빨리 해결책을 얻습니다.
MattoTodd

4
일광 절약 시간제를 자동으로 처리하는 것처럼 보이지 않습니다.
Gringo Suave

@GringoSuave : 의도하지 않았습니다. 이에 대한 규칙은 복잡하고 자주 변경됩니다.
Mark Tolonen

19

모호한 현지 시간에 해당하는 시간 (예 : DST 전환 중) 및 / 또는 현지 utc 오프셋이 현지 시간대의 시간에 따라 다른 경우에도 정확한 결과를 얻으려면 시간대를 사용하십시오 pytz.

#!/usr/bin/env python
from datetime import datetime
import pytz    # $ pip install pytz
import tzlocal # $ pip install tzlocal

local_timezone = tzlocal.get_localzone() # get pytz tzinfo
utc_time = datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
local_time = utc_time.replace(tzinfo=pytz.utc).astimezone(local_timezone)

10

이 답변은 이외의 다른 모듈을 사용하지 않으려는 경우 유용합니다 datetime.

datetime.utcfromtimestamp(timestamp)순진한 datetime객체 (인식 대상 아님)를 반환합니다 . 인식하는 것은 시간대를 인식하고 순진하지 않습니다. 시간대 간 (예 : UTC와 현지 시간 간) 변환하려는 경우 알고 있어야합니다.

시작 날짜를 인스턴스화하는 사람이 아니지만 datetimeUTC 시간 으로 순진한 객체를 만들 수있는 경우이 Python 3.x 코드를 사용하여 변환하려고 할 수 있습니다.

import datetime

d=datetime.datetime.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S") #Get your naive datetime object
d=d.replace(tzinfo=datetime.timezone.utc) #Convert it to an aware datetime object in UTC time.
d=d.astimezone() #Convert it to your local timezone (still aware)
print(d.strftime("%d %b %Y (%I:%M:%S:%f %p) %Z")) #Print it with a directive of choice

표준 시간대가 현재 MDT 인 경우 일광 절약 시간이 MST를 인쇄하므로 위의 코드에서 작동하지 않는다고 잘못 생각하지 않도록주의하십시오. 월을 8 월로 변경하면 MDT가 인쇄됩니다.

datetime파이썬 3.x에서도 인식 객체 를 얻는 또 다른 쉬운 방법 은 시작하도록 지정된 시간대로 객체를 만드는 것입니다. UTC를 사용한 예는 다음과 같습니다.

import datetime, sys

aware_utc_dt_obj=datetime.datetime.now(datetime.timezone.utc) #create an aware datetime object
dt_obj_local=aware_utc_dt_obj.astimezone() #convert it to local time

#The following section is just code for a directive I made that I liked.
if sys.platform=="win32":
    directive="%#d %b %Y (%#I:%M:%S:%f %p) %Z"
else:
    directive="%-d %b %Y (%-I:%M:%S:%f %p) %Z"

print(dt_obj_local.strftime(directive))

Python 2.x를 사용하는 경우 Python 2.x 에는 존재하지 않으므로 datetime.tzinfo인식 datetime객체 를 작성하는 데 도움 이되도록 서브 클래스 를 작성하고 사용해야합니다 datetime.timezone.


8

Django를 사용하는 경우 다음 timezone.localtime방법을 사용할 수 있습니다 .

from django.utils import timezone
date 
# datetime.datetime(2014, 8, 1, 20, 15, 0, 513000, tzinfo=<UTC>)

timezone.localtime(date)
# datetime.datetime(2014, 8, 1, 16, 15, 0, 513000, tzinfo=<DstTzInfo 'America/New_York' EDT-1 day, 20:00:00 DST>)

2

화살표 를 사용할 수 있습니다

from datetime import datetime
import arrow

now = datetime.utcnow()

print(arrow.get(now).to('local').format())
# '2018-04-04 15:59:24+02:00'

arrow.get()무엇이든 먹일 수 있습니다 . 타임 스탬프, iso 문자열 등


1

나는 전통적으로 이것을 프론트 엔드로 연기합니다. 백 엔드에서 시간을 타임 스탬프 또는 UTC로 다른 날짜 시간 형식으로 보낸 다음 클라이언트가 시간대 오프셋을 파악 하고이 데이터를 적절한 시간대로 렌더링하도록하십시오.

웹 응용 프로그램의 경우 이것은 자바 스크립트에서 수행하기가 매우 쉽습니다. 내장 메소드를 사용하여 브라우저의 시간대 오프셋을 쉽게 쉽게 파악한 다음 백엔드의 데이터를 올바르게 렌더링 할 수 있습니다.


3
이것은 단순히 디스플레이를 위해 현지화하는 많은 경우에 효과적입니다. 그러나 때때로 사용자 시간대를 기반으로 일부 비즈니스 로직을 수행해야하며 애플리케이션 서버 티어를 변환 할 수 있어야합니다.
Joe Holloway

1

calendar.timegm유닉스 시대 이후의 시간을 초로 time.localtime변환하고 다시 변환 하는 데 사용할 수 있습니다 .

import calendar
import time

time_tuple = time.strptime("2011-01-21 02:37:21", "%Y-%m-%d %H:%M:%S")
t = calendar.timegm(time_tuple)

print time.ctime(t)

제공합니다 Fri Jan 21 05:37:21 2011(UTC + 03:00 시간대이므로).


1
import datetime

def utc_str_to_local_str(utc_str: str, utc_format: str, local_format: str):
    """
    :param utc_str: UTC time string
    :param utc_format: format of UTC time string
    :param local_format: format of local time string
    :return: local time string
    """
    temp1 = datetime.datetime.strptime(utc_str, utc_format)
    temp2 = temp1.replace(tzinfo=datetime.timezone.utc)
    local_time = temp2.astimezone()
    return local_time.strftime(local_format)

utc = '2018-10-17T00:00:00.111Z'
utc_fmt = '%Y-%m-%dT%H:%M:%S.%fZ'
local_fmt = '%Y-%m-%dT%H:%M:%S+08:00'
local_string = utc_str_to_local_str(utc, utc_fmt, local_fmt)
print(local_string)   # 2018-10-17T08:00:00+08:00

예를 들어, 시간대는 ' +08 : 00 '입니다. 입력 utc = 2018-10-17T00 : 00 : 00.111Z 이면 출력을 얻습니다 = 2018-10-17T08 : 00 : 00 + 08 : 00


1
당신은 당신이 달성하고자하는 것과 다른 문제를 설명하는 나머지 텍스트를 일반 텍스트로 더 잘 설명해야합니다
m33n

1

여기에 대한 답변 에서 시간 모듈을 사용하여 utc에서 컴퓨터에 설정된 현지 시간으로 변환 할 수 있습니다.

utc_time = time.strptime("2018-12-13T10:32:00.000", "%Y-%m-%dT%H:%M:%S.%f")
utc_seconds = calendar.timegm(utc_time)
local_time = time.localtime(utc_seconds)

0

로컬 시스템 설정을 사용하여 시차를 해결하는 빠르고 더러운 버전입니다. 참고 : 현재 시스템이 실행되고 있지 않은 시간대로 변환해야하는 경우에는 작동하지 않습니다. BST 시간대에서 영국 설정으로 테스트했습니다.

from datetime import datetime
def ConvertP4DateTimeToLocal(timestampValue):
   assert isinstance(timestampValue, int)

   # get the UTC time from the timestamp integer value.
   d = datetime.utcfromtimestamp( timestampValue )

   # calculate time difference from utcnow and the local system time reported by OS
   offset = datetime.now() - datetime.utcnow()

   # Add offset to UTC time and return it
   return d + offset

그것이 있어야 datetime.fromtimestamp(ts): POSIX 타임 스탬프 (플로트 초) -> 현지 시간 날짜 객체 (OS 과거에 날짜를 윈도우에서 유닉스, 지역 시간대, 즉 과거의 UTC 오프셋을 기억하지만 경우 잘 작동)). 그렇지 않으면 pytz를 사용할 수 있습니다.
jfs

다음을 수행 할 것을 제안 할 수 offset = datetime.utcnow().replace(minute=0, second=0, microsecond=0) - datetime.now().replace(minute=0, second=0, microsecond=0) 있습니다.없이 마이크로 초 차이가 있습니다.
Erik van Oosten

@ErikvanOosten : datetime.fromtimestamp(ts)답변 대신 시도해 보셨습니까 ?
jfs

0

솔직한 답변을 편리한 방법으로 통합합니다 .

import calendar
import datetime

def to_local_datetime(utc_dt):
    """
    convert from utc datetime to a locally aware datetime according to the host timezone

    :param utc_dt: utc datetime
    :return: local timezone datetime
    """
    return datetime.datetime.fromtimestamp(calendar.timegm(utc_dt.timetuple()))
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.