Python 为什么date+;时间增量变成日期,而不是日期时间?
在Python中,在混合类型的数字操作中,较窄的类型是,例如Python 为什么date+;时间增量变成日期,而不是日期时间?,python,datetime,Python,Datetime,在Python中,在混合类型的数字操作中,较窄的类型是,例如int+float→ 浮动: In [57]: 3 + 0.1 Out[57]: 3.1 >>> 3 + 1.0 4.0 >>> 3 + 1 4 但是对于datetime.date,我们有datetime.date+datetime.timedelta→ 日期时间.date,而不是日期时间.datetime: In [58]: datetime.date(2013, 1, 1) + datetim
int
+float
→ <代码>浮动:
In [57]: 3 + 0.1
Out[57]: 3.1
>>> 3 + 1.0
4.0
>>> 3 + 1
4
但是对于datetime.date
,我们有datetime.date
+datetime.timedelta
→ <代码>日期时间.date,而不是日期时间.datetime
:
In [58]: datetime.date(2013, 1, 1) + datetime.timedelta(seconds=42)
Out[58]: datetime.date(2013, 1, 1)
为什么扩大推理适用于数字,而不适用于date
/datetime
/timedelta
(背景:我正在为一种文件格式编写一个读取例程,其中一个字段是年,一个字段是年中的一天,一个字段是从午夜开始的毫秒。当然,简单而明确的解决方案是
datetime.datetime(2013,1,1,0,0,0)+datetime.timedelta(秒=42)
,但同样可以推断,应该将3+0.1
重写为3.0+0.1
)当将时间增量和日期相加时,python将只查找时间增量的days属性。因此,如果加上42秒,日期将为0,并且不会影响您的日期。日期不是datetime的子类;datetime是一种复合类型,将日期
和时间
对象组合为一个。您不能决定从date
上的操作生成复合类型;时间
组件不是日期的一部分
另一方面,将整数定义为一种特殊浮点数(numbers.Integral
是numbers.Real
的一个间接子类),因此整数和浮点数之间的混合运算会产生基类型。并且浮点
不是复合类型,值的小数部分没有单独的类型
如果要从日期操作生成复合类型,则必须是显式的(显式优于隐式)。自己添加一个时间组件:
datetime.combine(yourdate, time.min) + yourdelta
其中,yourdate
可以通过分析您的年度加上年度输入日期的date.strtime(“%Y%j”)
生成
备选方案(有时根据
timedelta.seconds
值生成datetime
对象,或者总是)要求程序员再次打开日期组件(如果这是他们所期望的)。timedelta
对象不存储任何关于它是否只涉及日期的信息,或者也包括时代。(小时/分钟/秒/微秒数为0这一事实可能只是巧合!)
因此,假设我们有人只想操纵日期,而忽略时间,她会做类似于my\u new\u date=my\u old\u date+timedelta(days=1)
。当她发现my_new_date
现在是datetime
对象而不是date
对象时,她会非常惊讶,也可能会很恼火。行为是:
如果timedelta.days>0
,则日期2在时间上向前移动;如果timedelta.days<0
,则日期2在时间上向后移动。之后date2-date1==timedelta.days
timedelta.seconds
和timedelta.micross
被忽略。
(我的重点是,自从Python 2.3中添加了date
对象以来,这种行为就一直存在。)
我还没有找到任何证据来解释为什么这个模块是这样设计的。当然,也有像您这样的用例,您希望表示与一天开始的午夜对应的时间点。在这些情况下,必须来回转换是很烦人的。但是还有其他一些用例,您希望表示一整天(而不仅仅是当天的某个时间点),在这种情况下,您不希望在添加时间增量时意外地以部分天数结束
克里斯·威瑟斯建议改变这种行为,但蒂姆·彼得斯指出:
不兼容的文件化更改总是以这种方式工作的行为不太可能被接受
如果希望对象的行为类似于datetime.date
,但算术运算返回datetime.datetime
对象,那么编写一个对象应该不太困难:
from datetime import date, datetime, time, timedelta
def _part_day(t):
"""Return True if t is a timedelta object that does not consist of
whole days.
"""
return isinstance(t, timedelta) and (t.seconds or t.microseconds)
class mydate(date):
"""Subclass of datetime.date where arithmetic operations with a
timedelta object return a datetime.datetime object unless the
timedelta object consists of whole days.
"""
def datetime(self):
"""Return datetime corresponding to the midnight at start of this
date.
"""
return datetime.combine(self, time())
def __add__(self, other):
if _part_day(other):
return self.datetime() + other
else:
return super().__add__(other)
__radd__ = __add__
def __sub__(self, other):
if _part_day(other):
return self.datetime() - other
else:
return super().__sub__(other)
(这是未经测试的,但从这里开始工作应该不难。)可能的技术原因是Python中的内置类型通常不会从其操作符返回子类,即
date。\uuu add\uuu
不会返回datetime
。一致的行为要求date
和datetime
可以互换(它们不是)
date+timedelta
行为记录在案,不会改变。如果您想要datetime
作为结果;从日期创建日期时间:
dt = datetime(d.year, d.month, d.day)
从技术上讲,date.\uuuuuu add\uuuuu
可以将工作委托给timedelta.\uuuuu radd\uuuu
timedelta
分别存储天
,因此,如果我们想从date+timedelta
获取日期
或datetime
(这并不意味着我们应该这样做),就可以简单而有效地确定它是否代表天数的整数
<> >问题是<代码> 1 和<代码> 1 是相同的<代码>时间增量(1)< /代码>在这种情况下,即,如果我们允许<代码>日期+时间增量> /代码>返回“代码>日期时间< /代码>,那么如果我们只考虑类型,它应该返回<代码>日期时间< /代码>。
有一个先例是,int+int
根据结果返回int
或long
,即相同类型的操作可能只根据输入值返回不同类型的值。虽然date
和datetime
不如int
和long
那样可互换
date+timedelta
为某些值返回date
,为其他值返回timedelta
将创建
>>> 3 + 1.0
4.0
>>> 3 + 1
4
dt = datetime(year, 1, 1) + timedelta(days=day_of_year - 1, milliseconds=ms)