在Python中,在混合类型的数字操作中,较窄的类型被扩展为另一个的类型,例如int+ float→ float:
In [57]: 3 + 0.1
Out[57]: 3.1
Run Code Online (Sandbox Code Playgroud)
但是datetime.date,我们有datetime.date+ datetime.timedelta→ datetime.date,而不是 datetime.datetime:
In [58]: datetime.date(2013, 1, 1) + datetime.timedelta(seconds=42)
Out[58]: datetime.date(2013, 1, 1)
Run Code Online (Sandbox Code Playgroud)
为什么拓宽推理应用于数字,而不是date/ datetime/ timedelta?
(背景:我正在写一读例程,其中一个领域是一年的文件格式中,一个场中某一天的一年,场以来的毫秒数午夜当然,简单而明确的解决方案.datetime.datetime(2013, 1, 1, 0, 0, 0) + datetime.timedelta(seconds=42)但一个同样可以说一个人应该改写3 + 0.1为3.0 + 0.1)
行为记录在案:
如果
timedelta.days > 0,则向后移动date2,如果向后移动,则向前移动timedelta.days < 0.之后date2 - date1 == timedelta.days.timedelta.seconds并被timedelta.microseconds忽略.
(我的重点.由于在Python 2.3中添加了对象,因此这种行为保持不变date.)
我无法找到任何关于为什么模块设计如此的证据.当然,像你这样的用例你想要代表与一天开始的午夜相对应的时间点.在这些情况下,必须来回转换是令人讨厌的.但是还有其他一些用例需要代表一整天(而不仅仅是那天的某个时间点),在这种情况下,您不希望在添加timedeltas时意外地结束部分日期.
Chris Withers建议在第3249期更改行为,但Tim Peters指出:
对记录的始终工作的这种行为的不兼容的改变不太可能被接受.
如果你想要一个行为类似a的对象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)
Run Code Online (Sandbox Code Playgroud)
(这是未经测试的,但从这里开始工作应该不难.)
该timedelta对象不存储任何关于它是否只涉及日期或时间的信息.(小时/分钟/秒/微秒数为0的事实可能只是巧合!)
因此,假设我们有一个人只想操纵约会,无视时间,她会做类似的事情my_new_date = my_old_date + timedelta(days=1).她会非常惊讶并且可能会发现它my_new_date现在是一个datetime物体而不是一个date物体.
可能的技术原因是 Python 中的内置类型通常不会从其运算符返回子类,即date.__add__不会返回datetime。并且一致的行为需要date和datetime是可以互换的(它们不是)。
date + timedelta行为已记录并且不会改变。如果你想要datetime这样的结果;创建datetime日期d:
dt = datetime(d.year, d.month, d.day)
Run Code Online (Sandbox Code Playgroud)
从技术上讲,date.__add__可以将工作委托给timedelta.__radd__. timedelta单独存储days,因此可以简单有效地找出它是否代表整数天数,即,如果我们想要获取date或datetime来自date + timedelta(这并不意味着我们应该),我们就可以。
问题是1和在这种情况下1.0是相同的timedelta(1),即,如果我们允许date + timedelta返回datetime,那么如果我们只考虑类型,它应该返回datetime所有值。
int + int在返回int或long取决于结果时有一个先例,即相同类型的操作可能仅取决于输入值而返回不同类型的值。虽然date和datetime不像以前那样可以int互换long。
date + timedelta返回和date的某些值会造成混乱,除非我们也引入(如)或@Gareth Rees 提到的相关 Python 问题(如)。作为一个子类建议这条路线,尽管我听到一个论点说创建子类是一个错误。timedeltadatetimedate(y,m,d) == datetime(y,m,d)1 == 1.0date.today() < datetime.now()1 < 1.1datetimedatetimedate
所需的行为在包中实现dateutil:
>>> from datetime import date
>>> from dateutil.relativedelta import relativedelta
>>> date.today() + relativedelta(days=1)
datetime.date(2016, 5, 12)
>>> date.today() + relativedelta(days=1, seconds=1)
datetime.datetime(2016, 5, 12, 0, 0, 1)
Run Code Online (Sandbox Code Playgroud)
time() + timedelta无效,所以combine()在这里对我没有帮助。
combine()作品datetime.combine(d, time()) + timedelta_obj。不过,您可以将其写为:datetime(d.year, d.month, d.day) + timedelta_obj。
当然,简单而明确的解决方案是
datetime(2013, 1, 1, 0, 0, 0) + timedelta(seconds=42),但也可以重写3 + 0.1为3.0 + 0.1)
int+float始终是float:
>>> 3 + 1.0
4.0
>>> 3 + 1
4
Run Code Online (Sandbox Code Playgroud)
1.0与 和不同1;type(timedelta(1.0)) == type(timedelta(1))(除了相等之外,类型相同)。
我正在为一种文件格式编写一个读取例程,其中一个字段是年份,一个字段是一年中的某一天,一个字段是自午夜以来的毫秒数。
dt = datetime(year, 1, 1) + timedelta(days=day_of_year - 1, milliseconds=ms)
Run Code Online (Sandbox Code Playgroud)
日期不是datetime的子类; datetime是一种复合类型,将a date和一个time对象合二为一.你不能决定从date这里的操作中产生复合类型; 该time组件不是日期的一小部分.
另一方面,Python数字层次结构将整数定义为专用float类型(numbers.Integral是其间接子类numbers.Real),因此整数和浮点数之间的混合操作会导致生成基类型.并且float是不化合物类型,存在的值的小数部分没有单独的类型.
如果要从日期操作生成复合类型,则必须是显式的(并且显式优于隐式).自己添加时间组件:
datetime.combine(yourdate, time.min) + yourdelta
Run Code Online (Sandbox Code Playgroud)
其中,yourdate可以从生产date.strptime('%Y %j')的这一年加一天的最年输入的解析.
替代方案(有时基于值生成datetime对象,或者总是)需要程序员再次打开日期组件,如果这是他们期望的那样.timedelta.seconds
| 归档时间: |
|
| 查看次数: |
2948 次 |
| 最近记录: |