4

我住在英国,正在努力应对夏令时 BST 和时区。

这是我的代码:

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

设置这样的变量感觉非常错误,但是如果没有大量代码,我找不到任何优雅的方法来实现上述目标。我是否遗漏了什么,有没有办法(例如)读取系统时区?

4

5 回答 5

5

要将 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 日期时间转换为本地日期时间?.

于 2013-04-09T19:04:54.647 回答
4

您似乎在这里问了几个单独的问题。

首先,如果你只关心自己机器当前的本地时区,你不需要知道它是什么。只需使用本地到 UTC 功能。API 中有一些漏洞,但即使您找不到所需的功能,您也可以通过 POSIX 时间戳和fromtimestampandutcfromtimestamp方法从本地获取到 UT​​C,反之亦然。

如果您希望能够处理任何时区,请参阅文档顶部了解感知对象和朴素对象之间的区别,但基本上:感知对象是知道其时区的对象。所以,这就是你需要的。问题是,正如文档所说:

请注意,datetime 模块不提供具体的 tzinfo 类。需要任何详细程度的时区支持取决于应用程序。

支持时区的最简单方法是安装和使用第三方库pytz

同时,正如strftime()Behaviorstrptime()解释的那样,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 配方。

于 2013-04-09T19:12:20.053 回答
0

这是我用来做我认为你想做的事情的功能。这假设输入实际上是一个 gmt,或者更准确地说,一个 utc 日期时间对象:

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 上对我来说非常有效。

于 2013-04-09T23:36:52.267 回答
0

如果您想将 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() 之间的差异添加到从输入创建的时间元组中。

于 2013-04-09T19:36:17.083 回答
0

一个简单的函数来检查 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
于 2017-03-27T07:04:56.357 回答