我从来没有在UTC和UTC之间转换过时间。最近有一个请求,让我的应用程序具有时区感知,我一直在兜圈子。大量关于将本地时间转换为UTC的信息,我发现这些信息相当简单(可能我也做错了),但我找不到任何关于将UTC时间轻松转换为最终用户时区的信息。

简而言之,和android应用程序发送给我(appengine应用程序)数据,在该数据是一个时间戳。存储时间戳到utc时间我正在使用:

datetime.utcfromtimestamp(timestamp)

这似乎起作用了。当我的应用程序存储数据时,它被存储为5小时前(我是EST -5)

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

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

如何将此字符串转换为用户正确时区的日期时间?

另外,用户时区信息的推荐存储是什么?(你通常如何存储tz信息,如:“-5:00”或“EST”等?)我确信我第一个问题的答案可能包含第二个问题的答案的参数。


当前回答

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

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示例中的时间问题。还有埃里克·范·奥斯滕修正案中时间安排的问题。

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

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

其他回答

如果你想获得正确的结果,即使时间对应于一个不明确的本地时间(例如,在DST转换期间)和/或本地utc偏移量在本地时区的不同时间是不同的,那么使用pytz timezones:

#!/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)

如果您不想提供自己的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)

你可以使用日历。timegm将您的时间转换为Unix纪元和时间以来的秒数。转换回本地时间:

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)

给出星期五2011年1月21日05:37:21(因为我在UTC+03:00时区)。

从这里的答案,你可以使用时间模块从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)

简短而简单:

from datetime import datetime

t = "2011-01-21 02:37:21"
datetime.fromisoformat(t) + (datetime.now() - datetime.utcnow())