簡體   English   中英

將 UTC 日期時間字符串轉換為本地日期時間

[英]Convert UTC datetime string to local datetime

我從來不需要在 UTC 之間轉換時間。 最近有一個要求讓我的應用程序能夠感知時區,我一直在繞圈子。 很多關於將本地時間轉換為 UTC 的信息,我發現這些信息相當基本(也許我也做錯了),但我找不到任何關於輕松將 UTC 時間轉換為最終用戶時區的信息。

簡而言之,android 應用程序向我發送(appengine 應用程序)數據,並且在該數據中是一個時間戳。 將該時間戳存儲到我正在使用的UTC時間:

datetime.utcfromtimestamp(timestamp)

如果您不想提供自己的tzinfo對象,請查看python-dateutil庫。 它在zoneinfo (Olson) 數據庫之上提供tzinfo實現,以便您可以通過某種規范名稱來引用時區規則。

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包含的時區自動檢測方法(Yarin)

這是一個不依賴任何外部庫的彈性方法:

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

請參閱有關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

如果您想獲得正確的結果,即使在對應於不明確的本地時間(例如,在 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)

如果您不想使用除datetime之外的任何其他模塊,此答案應該會有所幫助。

datetime.utcfromtimestamp(timestamp)返回一個天真的datetime對象(不是一個有意識的對象)。 有意識的人是時區意識的,而幼稚的則不是。 如果您想在時區之間進行轉換(例如在 UTC 和本地時間之間),您需要一個有意識的。

如果您不是實例化開始日期的人,但您仍然可以在 UTC 時間創建一個簡單的datetime對象,您可能想嘗試使用這個 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。 您會注意到,如果將月份更改為八月,它將打印 MDT。

獲取感知datetime對象(也在 Python 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,你可能需要繼承datetime.tzinfo並使用它來幫助你創建一個有意識的datetime對象,因為datetime.timezone在 Python 2.x 中不存在。

如果使用 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>)

你可以使用箭頭

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 字符串等

franksands的答案合並為一種方便的方法。

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

您可以使用calendar.timegm將您的時間轉換為 Unix 紀元以來的time.localtime ,並將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 時區)。

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_tz_example_str = '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'

# call my function here
local_tz_str = utc_str_to_local_str(utc_tz_example_str, utc_fmt, local_fmt)
print(local_tz_str)   # 2018-10-17T08:00:00+08:00

當我輸入utc_tz_example_str = 2018-10-17T00:00:00.111Z 時,(UTC +00:00)
然后我會得到local_tz_str = 2018-10-17T08:00:00+08:00 (我的目標時區 +08:00)

參數utc_format是由您的特定utc_tz_example_str確定的格式。
參數local_fmt是最終所需的格式。

就我而言,我想要的格式是%Y-%m-%dT%H:%M:%S+08:00 ( +08:00 時區)。 您應該構建所需的格式。

我傳統上將此推遲到前端 - 從后端發送時間作為時間戳或其他一些 UTC 日期時間格式,然后讓客戶端計算出時區偏移量並在正確的時區中呈現這些數據。

對於 web 應用程序,這在 javascript 中很容易做到——您可以使用內置方法很容易地找出瀏覽器的時區偏移量,然后從后端正確呈現數據。

這里的答案,您可以使用 time 模塊將 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)

以下在美國西部的雲環境中對我有用:

import datetime
import pytz

#set the timezone
tzInfo = pytz.timezone('America/Los_Angeles')
dt = datetime.datetime.now(tz=tzInfo)
print(dt)

這是一個快速而骯臟的版本,它使用本地系統設置來計算時差。 注意:如果您需要轉換為當前系統未運行的時區,這將不起作用。我已在 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

這對我有用:

from django.utils import timezone
from datetime import timedelta,datetime

ist_time = timezone.now() + timedelta(hours=5,minutes=30)

#second method

ist_time = datetime.now() + timedelta(hours=5,minutes=30)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM