我有UTC偏移时如何创建tzinfo?

时间:2013-07-31 16:37:35

标签: python python-2.7

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

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

7 个答案:

答案 0 :(得分:25)

如果可以的话,请查看优秀的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 from here。这个名字真的可以是任何东西。如果你偏离,请小心,因为如果你使用依赖于名称的代码,它可能会在以后导致错误。

顺便说一下,如果您预先设置了时区名称,并且操作系统支持该名称,则可以改为使用gettz

# Replace the above with this
tzlocal = tz.gettz('IST')

答案 1 :(得分:16)

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):返回与datetime对象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

答案 2 :(得分:8)

您必须实现datetime.tzinfo类的子类。一般指南是described here,您还可以在其中找到自定义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

答案 3 :(得分:7)

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

答案 4 :(得分:6)

如果你有pytz:

tz = pytz.FixedOffset(180)
now = timezone.now()
local_now = tz.normalize(now.astimezone(tz))

答案 5 :(得分:0)

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

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

使用op在此问题中具有的偏移量构造示例tzname:

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

使用浏览器时区偏移量返回的示例构造tzname JavaScript新的Date()。getTimezoneOffset(),注意其中带有反斜杠的符号:

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

答案 6 :(得分:0)

很简单,只需import datetime

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

接下来,你可以,例如

>>> datetime.datetime.now(tz).isoformat(timespec='minutes')
'2021-08-03T18:07+05:30'