我不想使用pytz
库作为我正在处理的项目需要文书工作来介绍依赖项。如果我能在没有第三方图书馆的情况下实现这一目标,我会更开心。
当日期为夏令时,我在转换CET和UTC之间的日期时遇到问题。这与我的期望不同一小时:
>>> print from_cet_to_utc(year=2017, month=7, day=24, hour=10, minute=30)
2017-07-24T09:30Z
2017-07-24T08:30Z # expected
CET比UTC提前一小时,夏季提前2小时。所以我希望在仲夏的中欧10:30到达UTC时间的8:30。
功能是:
from datetime import datetime, tzinfo, timedelta
def from_cet_to_utc(year, month, day, hour, minute):
cet = datetime(year, month, day, hour, minute, tzinfo=CET())
utc = cet.astimezone(tz=UTC())
return '{:%Y-%m-%d:T%H:%MZ}'.format(utc)
我使用两个时区信息对象:
class CET(tzinfo):
def utcoffset(self, dt):
return timedelta(hours=1)
def dst(self, dt):
return timedelta(hours=2)
class UTC(tzinfo):
def utcoffset(self, dt):
return timedelta(0)
def dst(self, dt):
return timedelta(0)
答案 0 :(得分:3)
你应该仔细阅读tzinfo manual,因为这里有解释。
首先,dst()
通常应该返回timedelta(0)
或timedelta(hours=1)
,而不是2小时或更长时间,而且很少介于两者之间(例如30分钟)。这只是相对于正常TZ偏移的dst偏移,而不是dst模式下的完整TZ偏移。
其次,utcoffset()
必须已包含dst更正。在手册中描述的某些情况下也会使用dst()
方法(例如,如果dst是否生效,则用于检测),但除非您这样做,否则它不会自动应用于TZ偏移。
您的代码应如下所示:
from datetime import datetime, tzinfo, timedelta
class CET(tzinfo):
def utcoffset(self, dt):
return timedelta(hours=1) + self.dst(dt)
def dst(self, dt):
dston = datetime(year=dt.year, month=3, day=20)
dstoff = datetime(year=dt.year, month=10, day=20)
if dston <= dt.replace(tzinfo=None) < dstoff:
return timedelta(hours=1)
else:
return timedelta(0)
class UTC(tzinfo):
def utcoffset(self, dt):
return timedelta(0)
def dst(self, dt):
return timedelta(0)
def from_cet_to_utc(year, month, day, hour, minute):
cet = datetime(year, month, day, hour, minute, tzinfo=CET())
utc = cet.astimezone(tz=UTC())
return '{:%Y-%m-%d:T%H:%MZ}'.format(utc)
print from_cet_to_utc(year=2017, month=7, day=24, hour=10, minute=30)
# 2017-07-24:T08:30Z
在这里,我勇敢地假设DST生效20.03.YYYY - 19.10.YYYY包含,其中YYYY是日期/日期时间对象的年份。
通常这个on&amp; amp;关闭日期要复杂得多:转变发生在周日晚上,有时是在本月的最后一个星期日,并且在多年之间变化,有时在各州的主权之间变化(边界线也在多年来变化),以及夏令时法则和时间变化每隔几年就会发生变化(你好,俄罗斯)。
答案 1 :(得分:3)
只是补充@Sergey's answer。
要知道何时应该应用DST,您应该获取DST开始和结束时的日期/时间的历史数据,并检查是否必须将其应用于指定的datetime
。您可以从IANA database获取这些内容,也可以参考许多在线来源,例如timeanddate website。
另一个细节是 CET 是ambiguous name,因为它使用by more than one timezone。实时区域名称使用the ones defined by IANA database(始终采用Region/City
格式,例如Europe/Paris
或Europe/Berlin
。
我将以Europe/Berlin
timezone为例。在今年(2017年),柏林的DST于3月26日 th 开始:凌晨2点,时钟向前移动1小时向前,并且偏移从{{{ 1}}到+01:00
。
您还可以认为时钟从凌晨1:59直接跳到凌晨3点,这意味着当天在凌晨2点到凌晨2点59分之间的所有当地时间都不存在。这称为间隙,您应该检查这种情况(一种常见的方法是将凌晨2点调整到下一个有效小时 - 在这种情况下,在夏令时凌晨3点)。
在同一时区,2017年DST将于10月29日 th 结束:凌晨3点,时钟将返回 1小时至凌晨2点,偏移量将从+02:00
更改为+02:00
。
这意味着凌晨2点到凌晨2点59分之间的所有当地时间将存在两次:一次在DST(+01:00
),一次在非DST(+02:00
)。这称为重叠,在创建属于这种情况的+01:00
时,您必须决定选择创建哪一个(如果它在DST中是2 AM还是非-DST offset?你决定了!)。
PS:现在每个使用CET的欧洲国家都会在不同的年份采用它,所以如果你要处理旧日期,你也必须考虑它。
另一个细节是DST是由政府定义的,并且不能保证规则将永远这样,并且您必须相应地更新规则 - 使用{{1 },因为其更新是从IANA版本和published in PyPI生成的(感谢@Matt Johnson pointing this info)。
你确定文书工作比手工编写这些规则更糟吗?只需查看how to read IANA tz files,也许您就会改变主意。