Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/python-3.x/16.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python 3.x 如何创建适用于所有日期的时区感知时间对象?_Python 3.x_Pytz - Fatal编程技术网

Python 3.x 如何创建适用于所有日期的时区感知时间对象?

Python 3.x 如何创建适用于所有日期的时区感知时间对象?,python-3.x,pytz,Python 3.x,Pytz,我已经为这个问题挣扎了一段时间了。我觉得我很了解时区,我想我知道如何正确使用pytz,所以我通常使用它,我通常不会有任何问题。也许我正试图使用错误的工具来满足我的需求 在我当前的应用程序中,我需要在抽象的time对象中工作。也就是说,我关心16点发生的事情。我不在乎它发生在12月23日16:00。pytz似乎更喜欢使用datetime对象:这是有道理的。由于夏时制和历史原因等原因,它无法计算出偏移量,因为它根据日期而不同 我试图让用户协调世界各地的日常活动。如果日本的用户说活动时间是每天21:0

我已经为这个问题挣扎了一段时间了。我觉得我很了解时区,我想我知道如何正确使用pytz,所以我通常使用它,我通常不会有任何问题。也许我正试图使用错误的工具来满足我的需求

在我当前的应用程序中,我需要在抽象的
time
对象中工作。也就是说,我关心16点发生的事情。我不在乎它发生在12月23日16:00。pytz似乎更喜欢使用
datetime
对象:这是有道理的。由于夏时制和历史原因等原因,它无法计算出偏移量,因为它根据日期而不同

我试图让用户协调世界各地的日常活动。如果日本的用户说活动时间是每天21:00到23:00,我希望美国/中部的用户每天看到6:00到8:00。我还以为我有这个工作。。。直到两周前。看,DST在美国大部分地区刚刚结束,所以现在的6:00-8:00实际上是以前的7:00-9:00

这打破了我的想法,即我通常需要以UTC存储时间,然后转换它们仅用于查看。创建它的时区实际上非常重要。如果我们将其反转,并且美国时区的用户观察夏令时设置事件时间,那么日本的时间需要改变,即使他们不观察!如果我将该时间存储为UTC,在日本没有任何变化,但这不是我想要的功能

因此,我想用
tzinfo
存储为
time
对象。但是,如果没有日期,则无法创建具有精确pytz
tzinfo
的时间对象,但日期并不重要。如果我使用当前日期来计算
tzinfo
,那么一旦时区发生变化,它实际上就不再准确了

我想我的问题是:存储“东部时间下午4点”的最佳方式是什么?这种方式可以在世界任何地方,在未来的任何时候检索到?包括东部!我希望在夏令时和夏令时以外的时间是下午4点。我不能将其存储为UTC,因为UTC 12:00在整个一年中与UTC 12:00的时间相同,但我不希望这样。我想我想要的是一个“抽象的”或“临时的”
pytz.timezone
,在给出日期(查看日期)之前没有实际的偏移量。这是一件事吗?我在这个网站上读了无数的问题,包括python和pytz文档,但找不到类似的问题,也找不到任何有类似问题的人。一切似乎都在谈论特定的
日期时间
或只在
日期时间
内工作,但这似乎与我的问题无关

我的应用程序非常庞大,因此很难取出特定的部分,但我可以尝试展示我尝试过的内容以及为什么不起作用

event\u time=datetime.time(hour=12,tzinfo=pytz.timezone(“美国/东部”))
将是我理想的解决方案。但是使用pytz创建tzinfo不是一个好主意(由于历史原因,这会给我一个类似-5:04的偏移量)-有没有办法指定要使用的US/Eastern版本


datetime.now(pytz.timezone(“US/Eastern”)).replace(小时=12,分钟=0,秒=0,微秒=0)。timetz()
提供了一些看起来像我想要的东西,但只要US/Eastern没有改变,它就可以正常工作。如果我将此应用于DST更改之前我已移回的日期,它将为我提供13:00,这不是我想要的。

看起来pytz通过“本地化”方法提供了此功能,如`

从:

如果您坚持与《当地时报》合作,该图书馆将提供一个明确构建它们的工具:

eastern = timezone('US/Eastern')

loc_dt = datetime(2002, 10, 27, 1, 30, 00)
est_dt = eastern.localize(loc_dt, is_dst=True)
edt_dt = eastern.localize(loc_dt, is_dst=False)
print(est_dt.strftime(fmt) + ' / ' + edt_dt.strftime(fmt))
2002-10-27 01:30:00 EDT-0400 / 2002-10-27 01:30:00 EST-0500`

通过存储本地时间和本地时区,您可以在使用时将其转换,并将其转换为另一个地区的时区。

我构建了一个tzinfo类,自动处理DST的转换。我是从datetime文档中的USTimeZone类示例中得到这个想法的

这里的诀窍是pytz时区数据库拥有夏令时生效的所有历史日期。这也是为什么当您创建一个没有日期的datetime对象时,它会错误地转换DST;它基于数据库中的第一个条目

from datetime import datetime, tzinfo, timedelta
import pytz

ZERO = timedelta(0)

def format_timedelta(td):
    if td < timedelta(0):
        return '-' + format_timedelta(-td)
    else:
        # Change this to format positive timedeltas the way you want
        return str(td)



class WorldTimeZone(tzinfo):
    """
    A self adjusting according to DST rules in the PYTZ database tzinfo class
    See pytz.all_timezones for a list of all zone names and offsets.
    """

    def __init__(self, zone):
        """
        :param zone:  (str) Proper tzdatabase timze zone name. 
        """
        # initialize the pytz timezone with current time
        # this is done to avoid confusing tznames found in the start of the tz database
        # _utcoffset should always be STD rather than DST.
        self.pytzinfo = self.__getSTD(zone)
        self._utcoffset = self.pytzinfo._utcoffset


    @staticmethod
    def __getSTD(tname):
        """
        This returns a pytz timezone object normalized to standard time for the zone requested.
        If the zone does not follow DST or a future transition time cannot be found, it normalizes to NOW instead.

        :param tname:  Proper timezone name found in the tzdatabase. example: "US/Central"
        """

        # This defaults to the STD time for the zone rather than current time which could be DST
        tzone = pytz.timezone(tname)
        NOW = datetime.now(tz=pytz.UTC)
        std_date = NOW
        hasdst = False
        try:
            #transitions are in UTC.  They need to be converted to localtime once we find the correct STD transition.
            for utcdate, info in zip(tzone._utc_transition_times, tzone._transition_info):
                utcdate = utcdate.replace(tzinfo=pytz.UTC)
                utcoffset, dstoffset, tzname = info
                if dstoffset == ZERO:
                    std_date = utcdate
                if utcdate > NOW:
                    hasdst = True
                    break
        except AttributeError:
            std_date = NOW
        if not hasdst:
            std_date = NOW
        std_date = tzone.normalize(std_date)
        return std_date.tzinfo

    # This needs to be dynamic because pytzinfo updates everytime .dst() is called; which is a lot.
    @property
    def _dst(self):
        return self.pytzinfo._dst

    def __repr__(self):
        # return self.pytzinfo.__repr__()
        if self._dst:
            dst = 'DST'
        else:
            dst = 'STD'
        if self._utcoffset > timedelta(seconds=0):
            msg = '<WorldTimeZone %r %s+%s %s>'
        else:
            msg = '<WorldTimeZone %r %s%s %s>'
        return msg % (self.pytzinfo.zone, self.pytzinfo._tzname,
                      format_timedelta(self._utcoffset + self._dst), dst)

    def __str__(self):
        return "%s %s" % (self.pytzinfo._tzname, self.pytzinfo)

    def tzname(self, dt):
        # print "   TZNAME called"
        return "%s %s" % (self.pytzinfo._tzname, self.pytzinfo)

    def utcoffset(self, dt):
        # print "   UTCOFFSET CALLED"
        return self._utcoffset + self.dst(dt)

    def dst(self, dt):
        # print "   DST CALLED"
        if dt is None or dt.tzinfo is None:
            # An exception may be sensible here, in one or both cases.
            # It depends on how you want to treat them.  The default
            # fromutc() implementation (called by the default astimezone()
            # implementation) passes a datetime with dt.tzinfo is self.
            return ZERO

        assert dt.tzinfo is self  # WE ASSUME THE TZINFO ON THE DATE PASSED IN IS OUR TZINFO OBJECT.
        tmpdt = self.pytzinfo.normalize(dt)
        self.pytzinfo = tmpdt.tzinfo
        return tmpdt.tzinfo._dst
输出

2018-11-01 01:30:00 >> 2018-11-01 01:30:00-04:00 >> 2018-10-31 22:30:00-07:00
2018-11-06 01:30:00 >> 2018-11-06 01:30:00-05:00 >> 2018-11-05 22:30:00-08:00

我会尽力解释你的建议,因为我不知道这是否解决了我的问题。我想我想要一个模棱两可的时间。建议存储定期事件创建时的确切日期时间(例如,11月20日,东部时间下午4:00),然后,在计算以后显示的时间时,首先获取相关的小时,使用创建时使用的原始时区名称(可能是不同的偏移量)构造新的日期时间与该小时一起,然后使用新的
Datetime
计算查看器的显示时间?我想这可能行得通……嗨,伙计,我想你解释得对。在您的示例中,您希望下午4点的约会保持在下午4点,即使DST发生变化。这将如何影响在非DST时区的预约,或者这个问题是否会出现?例如,美国东部时区和日本的用户会与同一事件交互吗?是的,没错!每个人都应该在同一时间一起参加同一个活动,但对于创造者来说,无论DST如何,它都将始终在定义的时间进行;我的想法是存储没有日期的“loc_dt”,检查DST,然后用正确的DST值本地化事件创建者的本地_dt。最后,这个时间可以转换为活动参与者的其他时区。Marcel的答案处理了自定义类中的所有歧义。这太棒了!我想你已经涵盖了一切。非常感谢你。
2018-11-01 01:30:00 >> 2018-11-01 01:30:00-04:00 >> 2018-10-31 22:30:00-07:00
2018-11-06 01:30:00 >> 2018-11-06 01:30:00-05:00 >> 2018-11-05 22:30:00-08:00