我从来没有在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”等?)我确信我第一个问题的答案可能包含第二个问题的答案的参数。


当前回答

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

其他回答

请参阅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)

输出

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

我通常将此延迟到前端——从后端以UTC时间戳或其他日期时间格式发送时间,然后让客户端计算时区偏移量,并以适当的时区呈现此数据。

对于web应用程序,这在javascript中很容易做到——你可以使用内置方法很容易地计算出浏览器的时区偏移量,然后从后端正确地呈现数据。

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时区)。您应该构造所需的格式。

你可以使用箭头

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