46

我有一个时区与 UTC 的偏移量(以秒为单位)(19800),并且还具有字符串格式 - +0530

如何使用它们创建tzinfo实例?我查看了pytz,但在那里我只能找到将时区名称作为输入的 API。

4

7 回答 7

35

如果可以的话,看看优秀的dateutil包,而不是自己实现它。

具体来说,tzoffset。这是一个用 初始化的固定偏移量tzinfo实例offset,以秒为单位,这就是您要查找的内容。

更新

这是一个例子。一定pip install python-dateutil要先跑。

from datetime import datetime
from dateutil import tz

# First create the tzinfo object
tzlocal = tz.tzoffset('IST', 19800)

# Now add it to a naive datetime
local = naive.replace(tzinfo=tzlocal)

# Or convert another timezone to it
utcnow = datetime.utcnow().replace(tzinfo=tz.tzutc())
now = utcnow.astimezone(tzlocal)

IST 我从这里查了名字。这个名字真的可以是任何东西。如果您有偏差,请小心,因为如果您使用依赖名称的代码,以后可能会导致错误。

顺便说一句,如果您预先设置了时区名称,并且您的操作系统支持它,您可以使用gettz代替:

# Replace the above with this
tzlocal = tz.gettz('IST')
于 2015-02-02T03:38:29.893 回答
26

使用 Python 3.2 或更高版本,您可以使用内置的日期时间库执行此操作:

import datetime
datetime.timezone(-datetime.timedelta(hours=5, minutes=30)

要解决您的特定问题,您可以使用正则表达式:

sign, hours, minutes = re.match('([+\-]?)(\d{2})(\d{2})', '+0530').groups()
sign = -1 if sign == '-' else 1
hours, minutes = int(hours), int(minute)

tzinfo = datetime.timezone(sign * datetime.timedelta(hours=hours, minutes=minutes))
datetime.datetime(2013, 2, 3, 9, 45, tzinfo=tzinfo)
于 2016-05-08T08:27:09.080 回答
21

Python 标准库(8.1.6)说:

  • tzinfo 是一个抽象基类
  • datetime 模块不提供 tzinfo 的任何具体子类
  • 您需要派生一个具体的子类,并且(至少)提供您使用的日期时间方法所需的标准 tzinfo 方法的实现
  • tzinfo 的具体子类可能需要实现以下方法......如果有疑问,只需实现所有这些方法
    • tzinfo.utcoffset(self, dt) : 返回本地时间与 UTC 的偏移量,以 UTC 以东的分钟数为单位
    • tzinfo.dst(self, dt) :返回夏令时 (DST) 调整,以 UTC 以东的分钟数为单位,如果 DST 信息未知,则返回 None
    • tzinfo.tzname(self, dt) :以字符串形式返回日期时间对象dt对应的时区名称

这意味着您必须为 tzinfo 提供自己的实现。例如 :

class UTC0530(datetime.tzinfo):
    """tzinfo derived concrete class named "+0530" with offset of 19800"""
    # can be configured here
    _offset = datetime.timedelta(seconds = 19800)
    _dst = datetime.timedelta(0)
    _name = "+0530"
    def utcoffset(self, dt):
        return self.__class__._offset
    def dst(self, dt):
        return self.__class__._dst
    def tzname(self, dt):
        return self.__class__._name

用法 :

tz = UTC0530()
d = datetime.datetime.now(tz)
d.isoformat()

输出 :

2015-01-27T20:19:41.257000+05:30
于 2015-01-27T14:58:29.683 回答
10

你必须实现类的子datetime.tzinfo类。此处描述了一般指南,您还可以在其中找到自定义 tzinfo 实现的优秀示例。

这是示例(假设没有夏令时):

from datetime import tzinfo, timedelta, datetime
from pytz import UTC


class MyUTCOffsetTimezone (tzinfo):

    def __init__(self, offset=19800, name=None):
        self.offset = timedelta(seconds=offset)
        self.name = name or self.__class__.__name__

    def utcoffset(self, dt):
        return self.offset

    def tzname(self, dt):
        return self.name

    def dst(self, dt):
        return timedelta(0)


now = datetime.now(tz=UTC)
print now
# -> 2015-01-28 10:46:42.256841+00:00
print now.astimezone(MyUTCOffsetTimezone())
# -> 2015-01-28 16:16:42.256841+05:30
print datetime.now(MyUTCOffsetTimezone())
# -> 2015-01-28 16:16:42.256915+05:30
于 2015-01-27T14:03:03.640 回答
8

如果你有 pytz:

tz = pytz.FixedOffset(180)
now = timezone.now()
local_now = tz.normalize(now.astimezone(tz))
于 2015-09-11T07:03:17.543 回答
2

很简单,只有import datetime

>>> tz = datetime.timezone(datetime.timedelta(seconds=19800))

接下来,您可以,例如

>>> datetime.datetime.now(tz).isoformat(timespec='minutes')
'2021-08-03T18:07+05:30'
于 2021-08-03T12:37:59.167 回答
0

基于@Joe here的出色回答,我编写了一个函数,它对 pytz 进行猴子补丁以支持命名时区,例如“UTC-06:00”或“UTC+11:30”。我可以根据从浏览器发送给我的偏移量来构造其中一个名称,该偏移量只有一个由 Javascript new Date().getTimezoneOffset() 给出的整数,如此处所述并此处引用,然后我可以将名称发布为正常的时区名称可供我使用 pytz 的应用程序的其余部分使用。

这种机制也适用于这个问题中以秒为单位的偏移量的操作。

使用操作在此问题中的偏移量构造 tzname 示例:

minutes = offset // 60
tzname = 'UTC%s%02d:%02d' % (
    '-' if minutes < 0 else '+',
    abs(minutes) // 60, abs(minutes) % 60))

使用 JavaScript new Date().getTimezoneOffset() 返回的浏览器时区偏移量构造 tzname 的示例,值得注意的是它的符号相反:

tzname = (
    'UTC%s%02d:%02d' % (
        '-' if browser_tz_offset > 0 else '+', # reverse sign
        abs(browser_tz_offset) // 60, abs(browser_tz_offset) % 60))

使用命名区域构造一个 tzinfo 对象:

from datetime import datetime
import pytz
tz = pytz.timezone(tzname)  # tzname = e.g. 'UTC-06:00' or 'Europe/Madrid'
localized_now = datetime.now(tz)

我在应用程序启动期间调用此函数。

import re
import pytz
from dateutil import tz as dateutil_tz

def post_load_pytz_offset_timezones_server_wide():

    pristine_pytz_timezone = pytz.timezone

    def extended_pytz_timezone(zone):
        matches = re.match('^UTC([+-])([0-9][0-9]):([0-9][0-9])$', zone) if zone else None
        if matches:
            sign = -1 if matches.group(1) == '-' else 1
            minutes = int(matches.group(2)) * 60 + int(matches.group(3))
            tzinfo = dateutil_tz.tzoffset(zone, sign*minutes*60)
        else:
            tzinfo = pristine_pytz_timezone(zone)
    return tzinfo

    pytz.timezone = extended_pytz_timezone
于 2020-04-16T01:35:27.010 回答