我住在英国,正在努力适应夏令时和时区。
下面是我的代码:
TIME_OFFSET = 1 # 0 for GMT, 1 for BST
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
return (datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ') +
datetime.timedelta(hours=TIME_OFFSET)).strftime('%d/%m %H:%M')
像这样设置变量感觉非常错误,但我找不到任何优雅的方法来实现上面的目标,而不需要大量的代码。我是否错过了什么,是否没有办法(例如)读取系统时区? 将UTC转换为给定的时区:
from datetime import datetime
import pytz
local_tz = pytz.timezone("Europe/London") # time zone name from Olson database
def utc_to_local(utc_dt):
return utc_dt.replace(tzinfo=pytz.utc).astimezone(local_tz)
rfc3339s = "2013-04-08T22:35:00Z"
utc_dt = datetime.strptime(rfc3339s, '%Y-%m-%dT%H:%M:%SZ')
local_dt = utc_to_local(utc_dt)
print(local_dt.strftime('%d/%m %H:%M')) # -> 08/04 23:35
请参见如何仅使用python标准库将python utc日期时间转换为本地日期时间?
你好像问了几个不同的问题。
首先,如果你只关心你自己的机器当前的本地时区,你不需要知道它是什么。只需使用local-to-UTC函数。API中有一些漏洞,但即使你找不到你需要的函数,你也可以通过POSIX时间戳和fromtimestamp
和utcfromtimestamp
方法从本地到UTC或反之亦然。
如果你希望能够处理任何时区,请参阅文档顶部的感知对象和朴素对象之间的区别,但基本上:感知对象是知道其时区的对象。这就是你需要的。问题是,正如文档所说:
注意datetime模块没有提供具体的tzinfo类。支持时区的详细程度取决于应用程序。
支持时区最简单的方法是安装并使用第三方库pytz
。
同时,正如strftime()
和strptime()
的行为所解释的那样,strptime
总是返回一个朴素对象。然后,您必须调用replace
和/或astimezone
(取决于字符串是UTC时间还是本地时间)来获得具有正确时区的感知对象。
但是,即使有了这些,您仍然需要知道您所在的当地时区,这意味着您仍然需要一个常量。换句话说:
TIMEZONE = pytz.timezone('Europe/London')
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
utc_naive = datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ')
utc = utc_naive.replace(pytz.utc)
bst = utc.astimezone(TIMEZONE)
return bst.strftime('%d/%m %H:%M')
那么,如何让操作系统给你本地时区呢?好吧,这对于不同的平台是不同的,Python没有内置任何帮助。但是有一些不同的第三方库可以这样做,比如dateutil
。例如:
def RFC3339_to_localHHMM(input):
# Take an XML date (2013-04-08T22:35:00Z)
# return e.g. 08/04 23:35
utc = datetime.datetime.strptime(input, '%Y-%m-%dT%H:%M:%SZ')
bst = utc.astimezone(dateutil.tz.tzlocal())
return bst.strftime('%d/%m %H:%M')
但是现在我们又回到了原点。如果您想要的只是本地时区,那么实际上根本不需要时区(至少对于您的简单用例来说是这样)。因此,只有当您需要支持任何时区,并且也希望能够,例如,默认为您的本地时区时,才需要这样做(无需为感知和非感知情况编写所有代码的两个副本)。
(另外,如果您打算首先使用dateutil
,您可能希望使用它不仅仅是获取时区-它基本上可以取代您使用datetime
和pytz
所做的一切。)
当然,除了这些库之外,还有其他选择——搜索PyPI、Google和/或ActiveState食谱。
如果您想将UTC输入转换为本地时间,而不管您在哪个时区,请尝试以下操作:
def utctolocal(input):
if time.localtime()[-1] == 1: st=3600
else: st=0
return time.localtime(time.time()-time.mktime(time.gmtime())+time.mktime(time.localtime(time.mktime(time.strptime(input, '%Y-%m-%dT%H:%M:%SZ'))))+st)
相当长的代码,但它所做的只是将time.gmtime()和time.localtime()之间的差值添加到从输入创建的时间元组中。
这是我用来做我认为你想要的一个函数。这假定输入实际上是一个gmt,或者更准确地说,是一个utc datetime对象:
def utc_to_local(utc_dt):
'''Converts a utc datetime obj to local datetime obj.'''
t = utc_dt.timetuple()
secs = calendar.timegm(t)
loc = time.localtime(secs)
return datetime.datetime.fromtimestamp(time.mktime(loc))
就像你说的,这依赖于系统时区,这可能会给你不稳定的结果,正如一些评论所指出的。不过,它在我的Windows系统上运行得非常好。
检查UCT是否对应于伦敦的BST或GMT(用于设置上面的TIME_OFFSET)的简单函数
import datetime
def is_BST(input_date):
if input_date.month in range(4,9):
return True
if input_date.month in [11,12,1,2]:
return False
# Find start and end dates for current year
current_year = input_date.year
for day in range(25,32):
if datetime.datetime(current_year,3,day).weekday()==6:
BST_start = datetime.datetime(current_year,3,day,1)
if datetime.datetime(current_year,10,day).weekday()==6:
BST_end = datetime.datetime(current_year,10,day,1)
if (input_date > BST_start) and (input_date < BST_end):
return True
return False