将UTC日期时间字符串转换为本地日期时间
我之前从来没有需要把时间转换成UTC(协调世界时间)或从UTC转换回来的经历。最近有人要求我的应用程序能够识别时区,这让我有点头疼。我找到很多关于如何把本地时间转换成UTC的信息,这部分我觉得还算简单(也许我做错了),但我找不到关于如何轻松地把UTC时间转换成用户所在时区的信息。
简单来说,一个安卓应用会给我(appengine应用)发送数据,这些数据中包含一个时间戳。为了把这个时间戳存储为UTC时间,我使用了:
datetime.utcfromtimestamp(timestamp)
这看起来是有效的。当我的应用存储数据时,存储的时间比我所在的时间快了5个小时(我在东部标准时间,UTC-5)。
这些数据存储在appengine的BigTable中,当我取出数据时,它会以字符串的形式显示出来,像这样:
"2011-01-21 02:37:21"
我该如何把这个字符串转换成用户正确时区的日期时间呢?
另外,存储用户时区信息的推荐方式是什么?(通常你是如何存储时区信息的,比如“-5:00”或者“EST”等等?)我相信我第一个问题的答案可能会包含一个参数来回答第二个问题。
16 个回答
请查看datetime文档中关于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
这里有一种可靠的方法,不依赖任何外部库:
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
对象,可以看看 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)