Repository navigation
datetime: define division timedelta/timedelta #46958
Copy link
Copy link
Closed
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement
Description
| BPO | 2706 |
|---|---|
| Nosy | @jribbens, @amauryfa, @mdickinson, @vstinner, @merwok, @bitdancer |
| Files |
Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.
Show more details
GitHub fields:
assignee = 'https://github.com/mdickinson'
closed_at = <Date 2010-04-20.22:44:53.246>
created_at = <Date 2008-04-27.21:04:03.427>
labels = ['extension-modules', 'type-feature', 'library']
title = 'datetime: define division timedelta/timedelta'
updated_at = <Date 2010-04-21.17:54:08.177>
user = 'https://bugs.python.org/webograph'bugs.python.org fields:
activity = <Date 2010-04-21.17:54:08.177>
actor = 'mark.dickinson'
assignee = 'mark.dickinson'
closed = True
closed_date = <Date 2010-04-20.22:44:53.246>
closer = 'mark.dickinson'
components = ['Extension Modules', 'Library (Lib)']
creation = <Date 2008-04-27.21:04:03.427>
creator = 'webograph'
dependencies = []
files = ['10126', '10946', '12010', '12011', '16999', '17003']
hgrepos = []
issue_num = 2706
keywords = ['patch']
message_count = 39.0
messages = ['65902', '70018', '75876', '75877', '75878', '75880', '75881', '75882', '75883', '75884', '75892', '75894', '75895', '75908', '75909', '75913', '75917', '77646', '83416', '83447', '83453', '83936', '84131', '84151', '102956', '102962', '103615', '103631', '103634', '103635', '103636', '103637', '103638', '103653', '103664', '103787', '103788', '103867', '103872']
nosy_count = 11.0
nosy_names = ['jribbens', 'amaury.forgeotdarc', 'mark.dickinson', 'vstinner', 'jess.austin', 'fredrikj', 'webograph', 'eric.araujo', 'r.david.murray', 'tleeuwenburg@gmail.com', 'Alexander.Belopolsky']
pr_nums = []
priority = 'normal'
resolution = 'accepted'
stage = 'resolved'
status = 'closed'
superseder = None
type = 'enhancement'
url = 'https://bugs.python.org/issue2706'
versions = ['Python 3.2']Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
extension-modulesC modules in the Modules dirC modules in the Modules dirstdlibStandard Library Python modules in the Lib/ directoryStandard Library Python modules in the Lib/ directorytype-featureA feature request or enhancementA feature request or enhancement
Activity
webograph commentedon Apr 27, 2008
i suggest that division be defined for timedelta1/timedelta2, in that
sense that it gives how many times timedelta2 fits in timedelta1 (ie the
usual meaning of division), using integer arithmetics for floor division
(//) and returning float for truediv (/ after
from __future__ import division)use case
--------
aside from the obvious how-many-times-does-a-fit-into-b, this solves the
issue of having individual methods for conversion to a number of
seconds, hours, days or nanocenturies (as described in bpo-1673409).
example:
history
-------
this issue follows a discussion on python-list, re-initiated by [1].
there have previously been similar feature requests on datetime, most of
which have been rejected due to ambiguities (e.g. [2]), conflicts with
time_t or issues with time zones.
the only issue i've seen that can be relevant here is the
integer-vs-float discussion, which is here handled by floordiv (//) and
truediv.
patch
-----
i've written a patch against svn trunk revision 62520.
it uses function pointers to reduce code duplication; in case this
inappropriate here, i also have a pointerless version.
i familiar with c but not experienced, especially with the python ways
of writing c. most of the code is just adapted from other functions in
the same files, so it is probably, but should nevertheless checked with
special care.
i've also added test, but am not sure what has to be tested and what not.
compatibility
-------------
only cases in which division would fail without the patch are changed.
this will be a problem if (and only if) someone divides unknown objects
and waits for TypeError to be raised.
such behavior is probably rare.
[1] <mid:4813CD56.40800@eml.cc>,
http://mail.python.org/pipermail/python-list/2008-April/488406.html
[2] http://mail.python.org/pipermail/python-dev/2002-March/020604.html
webograph commentedon Jul 19, 2008
this is the mentioned patch without the function pointers, in case it
better fits the python coding style.
abalkin commentedon Nov 14, 2008
I attaching webograph's patch updated to revision 67223 where I added a
few tests.
I am +1 on the floor divide changes (allowing timedelta // timedelta),
but I am not sure how true division should work if at all. For the sake
of argument, let's assume from __future__ import division or py3k.
Currently:
With this patch, timedelta(1)/2 is still unsupported, but
Note that this is probably correct behavior because timedelta/int true
division does not make much sense, but there is a proposal (see bpo-1083) to make timedelta/int equivalent to timedelta//int. (I am
against bpo-1083 proposal and for webograph's approach, but this needs
to be further discussed.)
Also, I've added a test that demonstrates the following behavior:
This is not a bug in webograph's patch, but rather a bug in long true
division, but it shows that true division may not be as useful as it
seems.
vstinner commentedon Nov 14, 2008
Why not also implementing divmod()? It's useful to split a timedelta
into, for example, (hours, minutes, seconds):
My implementation gives divmod(timedelta, timedelta) -> (long,
timedelta). It's a little bit strange to get two different types in
the result. The second return value is the remainder. My example works
in the reverse order of the classical code:
abalkin commentedon Nov 14, 2008
On Fri, Nov 14, 2008 at 12:51 PM, STINNER Victor <report@bugs.python.org> wrote:
I agree and in this case mod should probably be implemented too.
With your patch:
abalkin commentedon Nov 14, 2008
Also, why not
?
And where do we stop? :-)
vstinner commentedon Nov 14, 2008
Since timedelta(3) // 2 is already accepted, divmod should also accept
integers (but not float).
With the last patch and "from __future__ import division", we support:
timedelta // <timedelta or int>
timedelta / timedelta
divmod(timedelta, timedelta)
What do you think about:
timedelta / <timedelta or int or float> # only with __future__.divison
timedelta // <timedelta or int>
timedelta % <timedelta or int>
divmod(timedelta, <timedelta or int>)
with:
timedelta // int -> timedelta
timedelta // timedelta -> int
timedelta % int -> timedelta
timedelta % timedelta -> int
divmod(timedelta, int) -> (timedelta, timedelta)
divmod(timedelta, timedelta) -> (int, timedelta)
timedelta / <anything> -> float # __future__.divison
abalkin commentedon Nov 14, 2008
While I agree that divmod may be useful, your particular use case is
not convincing. The same can be done easier without divmod:
or you can convert delta to time using an arbitrary anchor date and
extract hms that way:
(1, 24, 19)
(depending on your needs you may want to add delta.days*24 to the hours)
On Fri, Nov 14, 2008 at 12:51 PM, STINNER Victor <report@bugs.python.org> wrote: > > STINNER Victor <victor.stinner@haypocalc.com> added the comment: > > Why not also implementing divmod()? It's useful to split a timedelta > into, for example, (hours, minutes, seconds): > > def formatTimedelta(delta): > """ > >>> formatTimedelta(timedelta(hours=1, minutes=24, seconds=19)) > '1h 24min 19sec' > """ > hours, minutes = divmodTimedelta(delta, timedelta(hours=1)) > minutes, seconds = divmodTimedelta(minutes, timedelta(minutes=1)) > seconds, fraction = divmodTimedelta(seconds, timedelta(seconds=1)) > return "{0}h {1}min {2}sec".format(hours, minutes, seconds) >abalkin commentedon Nov 14, 2008
On Fri, Nov 14, 2008 at 1:28 PM, STINNER Victor <report@bugs.python.org> wrote:
..
+1
+1
+1
timedelta % float -> timedelta (because int % float -> int works) ?
+1
+1
divmod(timedelta, float) -> (timedelta, timedelta) ?
-1
Only timedelta / timedelta should produce dimensionless numbers.
timedelta / <float or int> should be disallowed in true division mode.
I am +0 on timedelta / timedelta -> float in true division mode.
abalkin commentedon Nov 14, 2008
Oops, the tracker ate some lines from e-mail. Reposting through the
web:
On Fri, Nov 14, 2008 at 1:28 PM, STINNER Victor <report@bugs.python.org>
wrote:
..
timedelta % float -> timedelta (because int % float -> int works) ?
divmod(timedelta, float) -> (timedelta, timedelta) ?
Only timedelta / timedelta should produce dimensionless numbers.
timedelta / <float or int> should be disallowed in true division mode.
I am +0 on timedelta / timedelta -> float in true division mode.
Reply
Forward
vstinner commentedon Nov 14, 2008
OMG, this is ugly! Conversion to string and reparse the formatted text :-/
Your code doesn't work with different units than hours, minutes or seconds:
How? I don't understand your suggestion.
The goal of the new operators (timedelta / timedelta, divmod(timedelta,
timedelta), etc.) is to avoid the use of the timedelta "internals" (days,
seconds and microseconds attributes) and give a new "natural" way to process
time deltas.
abalkin commentedon Nov 14, 2008
haypo> How? I don't understand your suggestion.
Sorry, another case of mail to tracker bug. Here is what I wrote:
"""
.. you can convert delta to time using an arbitrary anchor date and
extract hms that way:
(depending on your needs you may want to add delta.days*24 to the hours)
"""
but tracker ate the '>>>' lines :-(
vstinner commentedon Nov 14, 2008
@WeboGraph: time_gmtime() and time_localtime() already use function
pointer. I prefer function pointer than code duplication!
17 remaining items
mdickinson commentedon Apr 19, 2010
By the way, the patch looks good to me, as far as it goes, and I'm +1 on adding all this. I only have the tiniest of nits:
the patch deletes a line at the top of Lib/test/test_datetime.py, for no apparent reason
in delta_add, I think the added 'if' block should be an 'else if' (yes, I know this is excessively picky ;)
the brace style for if blocks is inconsistent: please put the opening brace on the same line as the if.
One other thought: with this division operation added, it might be nice to add constants like td_hour, td_minute, etc. to the module. Then the perennial 'how can I convert my timedelta x to minutes' questions could be answered with 'just do x/td_minute'. I would personally find x/td_second to be a more obvious and natural way to find the total number of seconds in a timedelta than x.total_seconds. I also quite like the idea of being able to create a 2.5-hour timedelta with something like
2*td_hour + 30*td_minute
On the other hand, maybe such constants would just be added clutter, since it's easy to create them when needed.
mdickinson commentedon Apr 19, 2010
Tennessee, are you still tracking this issue? If not, can I steal it from you. :)
Mmm. Interesting. :)
I think it would be fine to add timedelta % timedelta in this patch, and then open another feature request for timedelta % int and friends as you suggest. I don't think divmod(timedelta, timedelta) should go in if timedelta % timedelta doesn't also go in.
Perhaps; I haven't seen much opposition to these ideas anyway---I think the only reason they haven't been implemented yet is lack of round-tuits.
I'd be +1 on accepting the current patch if timedelta % timedelta were added to it.
mdickinson commentedon Apr 19, 2010
Hmm. Having timedelta // int work is *really* peculiar, since it can only be made sense of with reference to some implicit particular chosen unit of time; in this case, that unit of time is apparently microseconds, as far as I can tell.
Surely there aren't any applications for timedelta // int?! The operation just doesn't make dimensional sense, since it involves taking floor of a timedelta.
I vote -3.2 minutes on extending this craziness by adding timedelta % int or divmod(timedelta, int).
AlexanderBelopolsky commentedon Apr 19, 2010
I should be able to add timedelta % timedelta and fix the nits that Mark mentioned tonight.
tleeuwenburggmailcom commentedon Apr 19, 2010
On Tue, Apr 20, 2010 at 6:46 AM, Mark Dickinson <report@bugs.python.org>wrote:
Hi Mark,
Please feel free to steal it from me! Wonderful to see some movement on this
issue...
I'm an incrementalist -- I'm happy with one step at a time, so for what it's
worth I'd be happy to see divmod go in alone with % to be added later.
However, seeing as I'm really contributing, I'd say feel free to disregard
my vote of +1... :)
Regards,
-Tennessee
AlexanderBelopolsky commentedon Apr 20, 2010
New patch, issue2706a.diff, implements timedelta % timedelta and addresses Mark's code review comments.
With respect to Mark's
"""
One other thought: with this division operation added, it might be nice to add constants like td_hour, td_minute, etc. to the module. Then the perennial 'how can I convert my timedelta x to minutes' questions could be answered with 'just do x/td_minute'. I would personally find x/td_second to be a more obvious and natural way to find the total number of seconds in a timedelta than x.total_seconds. I also quite like the idea of being able to create a 2.5-hour timedelta with something like
2*td_hour + 30*td_minute
On the other hand, maybe such constants would just be added clutter, since it's easy to create them when needed.
"""
I dislike this proposal for the same reason as Mark likes it: 2*td_hour + 30*td_minute == timedelta(hours=2, minutes=30) is a violation of TOOWTDI.
mdickinson commentedon Apr 20, 2010
Stealing from Tennessee...
Patch committed to py3k in r80290, r80291, with some minor tweaks and fixes:
lambda in favour of using the operator module
Thanks, Alexander!
mdickinson commentedon Apr 20, 2010
Grr. s/whatsnew/versionadded/
AlexanderBelopolsky commentedon Apr 21, 2010
Can someone (Mark?) add an acknowledgment for Victor Stinner to the NEWS file? My py3k patch was 90% code from Victor's trunk patch.
mdickinson commentedon Apr 21, 2010
Ah, yes. Sorry, Victor! There's actually no acknowledgement in Misc/NEWS: it's not *that* common to put acknowledgements there, and I'm not sure it's necessary here, but I've fixed the commit message.