优雅的方式来调整Python中的日期时区

时间:2013-04-09 18:51:09

标签: python date time timezone timezone-offset

我在英国工作,并且正在努力应对夏令时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')

设置这样的变量感觉非常错误,但我无法找到任何优雅的方法来实现上述内容而不会产生大量的代码。我错过了什么,并且没有办法(例如)读取系统时区吗?

5 个答案:

答案 0 :(得分: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

另见How to convert a python utc datetime to a local datetime using only python standard library?

答案 1 :(得分:3)

你好像在这里问几个问题。

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

如果您希望能够处理任何时区,请参阅the docs的顶部,了解有意识和天真对象之间的区别,但基本上:知道对象是知道的对象它的时区。所以,这就是你所需要的。问题在于,正如文档所说:

  

请注意,datetime模块不提供具体的tzinfo类。无论在何种级别的细节上都需要支持时区取决于应用程序。

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

同时,正如strftime() and strptime() Behavior解释的那样,utcfromtimestamp总是会返回一个天真的对象。然后,您必须调用replace和/或strptime(取决于字符串是UTC时间还是本地时间)以获得充满正确时区的感知对象。

但是,即使有了这一切,你仍然需要知道你所在的当地时区,这意味着你仍然需要一个常数。换句话说:

astimezone

那么,你如何让操作系统为你提供当地时区?嗯,这对于不同的平台来说是不同的,并且Python没有内置任何帮助。但是有一些不同的第三方库可以做,例如dateutil。例如:

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

但是现在我们已经完整了。如果您想要的只是本地时区,那么您根本不需要时区(至少对于您的简单用例)。因此,只有在您需要支持任何时区时才需要这样做,并且希望能够,例如,默认为您的本地时区(无需为您的所有代码编写两份副本)意识到和天真的情况)。

(另外,如果您首先要使用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') ,您可能希望将其用于获取时区以外 - 它基本上可以替换您正在使用的{{1} 1}}和dateutil。)

当然除了这些库之外还有其他选项 - 搜索PyPI,Google和/或ActiveState配方。

答案 2 :(得分: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()之间的差异添加到从输入创建的时间元组中。

答案 3 :(得分:0)

这是我用来做我想你想要的功能。这假设输入实际上是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上对我来说非常完美。

答案 4 :(得分:0)

检查UCT是否与伦敦或GMT的BST相对应的简单函数(用于设置上面的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