使用Python将UTC日期时间字符串转换为本地日期时间

Mat*_*odd 193 python datetime utc localtime

我从来没有把时间转换成UTC.最近有一个请求要让我的应用程序能够识别时区,而且我一直在圈子里跑.关于将本地时间转换为UTC的大量信息,我发现它相当基本(也许我也做错了),但我找不到任何有关将UTC时间轻松转换为最终用户时区的信息.

简而言之,Android应用程序向我发送(appengine app)数据,在该数据中是一个时间戳.要将时间戳存储到我正在使用的时间:

datetime.utcfromtimestamp(timestamp)
Run Code Online (Sandbox Code Playgroud)

这似乎有效.当我的应用程序存储数据时,它将提前5小时存储(我是EST -5)

数据存储在appengine的BigTable上,当检索到它时,它就像一个字符串一样:

"2011-01-21 02:37:21"
Run Code Online (Sandbox Code Playgroud)

如何在用户正确的时区将此字符串转换为DateTime?

此外,用户时区信息的推荐存储是什么?(你怎么通常存储TZ信息,即:"-5:00"或"EST"等等等等),我敢肯定的答案,我的第一个问题可能包含一个参数的回答第二个.

Joe*_*way 366

如果您不想提供自己的tzinfo对象,请查看python-dateutil库.它tzinfozoneinfo(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)
Run Code Online (Sandbox Code Playgroud)

编辑扩展示例以显示strptime用法

编辑2固定API用法以显示更好的入口点方法

编辑3包含时区的自动检测方法(Yarin)

  • @MattoTodd:[utc - >本地转换在`dateutil`中断](https://github.com/dateutil/dateutil/issues/112),使用[`pytz`代替](http://stackoverflow.com/一个/四千二百七十九分之三千二百九十零万四千八百十二). (2认同)
  • @JFSebastian 这已在 [#225](https://github.com/dateutil/dateutil/pull/225) 中修复 (2认同)
  • @briankip这取决于您的应用程序需要多么复杂,但在一般应用程序中,是的,这是一个问题.首先取决于一年中的什么时间,加/减的小时数可能会改变,因为一些时区会尊重DST,而其他时区则不会.其次,时区规则会随着时间的推移而随意更改,因此,如果您使用过去的日期/时间,则需要应用当时有效的规则,而不是当前时间.这就是为什么最好使用在幕后利用Olson TZ数据库的API. (2认同)

Dav*_*ter 38

这是一个不依赖于任何外部库的弹性方法:

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
Run Code Online (Sandbox Code Playgroud)

这避免了DelboyJay示例中的时序问题.Erik van Oosten的修正案中的时间问题较少.

作为一个有趣的脚注,上面计算的时区偏移量可能与以下看似等效的表达式不同,可能是由于夏令时规则更改:

offset = datetime.fromtimestamp(0) - datetime.utcfromtimestamp(0) # NO!
Run Code Online (Sandbox Code Playgroud)

更新:此代码段具有使用当前时间的UTC偏移量的弱点,该偏移量可能与输入日期时间的UTC偏移量不同.有关其他解决方案,请参阅此答案的评论

要绕过不同的时间,从传入的时间开始抓住纪元时间.这就是我的工作:

def utc2local (utc):
    epoch = time.mktime(utc.timetuple())
    offset = datetime.fromtimestamp (epoch) - datetime.utcfromtimestamp (epoch)
    return utc + offset
Run Code Online (Sandbox Code Playgroud)

  • @Mike_K:但是不对.由于其他原因,它不支持过去具有不同utc偏移的DST或时区.没有`pytz`-like db的完全支持是不可能的,参见PEP-431.虽然你可以在已经有历史时区数据库的系统上编写仅适用于stdlib的解决方案,例如Linux,OS X,但请参阅[我的回答](http://stackoverflow.com/a/13287083/4279). (6认同)
  • 这很有效,除了时间和日期时间之外不需要任何东西。 (2认同)
  • @DavidFoster:您的代码也可能在Linux和OS X上失败.你和[我的stdlib-only解决方案](http://stackoverflow.com/a/13287083/4279)之间的区别在于你的*current*offset可能与`utc_datetime`时间的utc偏移不同. (2认同)
  • 好决定。这是一个非常微妙的区别。UTC 偏移量也可以随时间变化。*叹* (2认同)

Mar*_*nen 21

请参阅tzinfo对象的datetime文档.您必须实现自己想要支持的时区.这些是文档底部的示例.

这是一个简单的例子:

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)
Run Code Online (Sandbox Code Playgroud)

产量

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
Run Code Online (Sandbox Code Playgroud)

  • 看起来不会自动处理夏令时. (4认同)

jfs*_*jfs 17

如果您希望获得正确的结果,即使对应于模糊的本地时间(例如,在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)
Run Code Online (Sandbox Code Playgroud)


Jie*_*Jie 8

以下内容在美国西部的云环境中对我有用:

import datetime
import pytz

#set the timezone
tzInfo = pytz.timezone('America/Los_Angeles')
dt = datetime.datetime.now(tz=tzInfo)
print(dt)
Run Code Online (Sandbox Code Playgroud)


frm*_*ryr 7

如果使用django,则可以使用timezone.localtime方法(请参阅https://docs.djangoproject.com/en/dev/topics/i18n/timezones/).

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>)
Run Code Online (Sandbox Code Playgroud)


Shu*_*ule 7

如果您不想使用以外的任何其他模块,此答案应该会有所帮助datetime

datetime.utcfromtimestamp(timestamp)返回一个天真的datetime对象(不是一个有意识的对象)。知道的人知道时区,而天真的不是。如果要在时区之间进行转换(例如,在UTC与本地时间之间进行转换),则需要一个有意识的人。

如果您不是实例化开始日期的人,但仍可以datetime在UTC时间创建一个天真的对象,则可能需要尝试使用以下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
Run Code Online (Sandbox Code Playgroud)

注意不要误认为如果您的时区当前是MDT,则上述代码将显示MST,因此夏令时不适用于上述代码。您会注意到,如果您将月份更改为8月,它将打印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))
Run Code Online (Sandbox Code Playgroud)

如果使用Python 2.x,则可能必须继承datetime.tzinfo并使用它来帮助您创建感知datetime对象,因为datetime.timezonePython 2.x中不存在该对象。


Mar*_*ark 6

将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()))
Run Code Online (Sandbox Code Playgroud)


d21*_*d3q 5

您可以使用箭头

from datetime import datetime
import arrow

now = datetime.utcnow()

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

你可以arrow.get()用任何东西喂养。时间戳、iso 字符串等