Discussion:
Another surprise from the datetime module
(too old to reply)
Roy Smith
2014-01-30 17:32:31 UTC
Permalink
I was astounded just now to discover that datetime.timedelta doesn't
have a replace() method (at least not in Python 2.7). Is there some
fundamental reason why it shouldn't, or is this just an oversight?

My immediate use case was wanting to print a timedelta without the
fractions of seconds. The most straight-forward is:

print td.replace(microseconds=0)

but that doesn't work. Yes, I know I can use strftime, but (as I've
mentioned before :-)), that requires dragging up the reference page to
figure out what grotty little format string I need. The brute-force

print timedelta(seconds=int(td.total_seconds()))

is easier than that, but plain old replace() would be even easier.
Mark Lawrence
2014-01-30 18:03:17 UTC
Permalink
Post by Roy Smith
I was astounded just now to discover that datetime.timedelta doesn't
have a replace() method (at least not in Python 2.7). Is there some
fundamental reason why it shouldn't, or is this just an oversight?
My immediate use case was wanting to print a timedelta without the
print td.replace(microseconds=0)
but that doesn't work. Yes, I know I can use strftime, but (as I've
mentioned before :-)), that requires dragging up the reference page to
figure out what grotty little format string I need. The brute-force
print timedelta(seconds=int(td.total_seconds()))
is easier than that, but plain old replace() would be even easier.
datetime.timedelta doesn't have a strftime method either.

AttributeError: 'datetime.timedelta' object has no attribute 'strftime'
--
My fellow Pythonistas, ask not what our language can do for you, ask
what you can do for our language.

Mark Lawrence
Neil Cerutti
2014-01-30 18:36:34 UTC
Permalink
Post by Roy Smith
I was astounded just now to discover that datetime.timedelta
doesn't have a replace() method (at least not in Python 2.7).
Is there some fundamental reason why it shouldn't, or is this
just an oversight?
My immediate use case was wanting to print a timedelta without
print td.replace(microseconds=0)
That would be nice.

In the meantime, this works for your use case:

td -= td % timedelta(seconds=1)
--
Neil Cerutti
Cameron Simpson
2014-01-31 00:06:31 UTC
Permalink
Post by Neil Cerutti
Post by Roy Smith
I was astounded just now to discover that datetime.timedelta
doesn't have a replace() method (at least not in Python 2.7).
Is there some fundamental reason why it shouldn't, or is this
just an oversight?
My immediate use case was wanting to print a timedelta without
print td.replace(microseconds=0)
That would be nice.
td -= td % timedelta(seconds=1)
Hmm. I do not like the replace() as suggested.

Firstly, replace is a verb, and I would normally read
td.replace(microseconds=0) as an instruction to modify td in place.
Traditionally, such methods in python return None.
So you would need:

td.replace(microseconds=0)
print td

Then, if the intent is to modify td in place, I would far prefer a system of
properties on timedelta objects, eg:

# print the microseconds part
print td.microseconds

# set the microseconds part to zero
td.microseconds = 0

# print the modified timedelta
print td

Also, clearly, such a system needs definition: is "microseconds"
the sub-millisecond fraction or the sub-second fraction, expressed
in microsecond units?

Alternatively, if td.replace() is intened to return a new timedelta
with the specified properties, perhaps another factory would be
cleaner:

td2 = datetime.timedelta(td, microseconds=0)

with a bunch of optional parameters like microseconds for modifying
the initial value (used at call, as above).

Finally, how much of Roy's original wish is addressable by format
strings to print with a specified precision? No good for arithmetic,
but perhaps ok for presentation.

Cheers,
--
Cameron Simpson <***@zip.com.au>

I knew I was a real biker when I pulled up beside a car at a stoplight and
the people inside locked all the doors.
Ben Finney
2014-01-31 00:35:14 UTC
Permalink
Post by Cameron Simpson
Hmm. I do not like the replace() as suggested.
Firstly, replace is a verb, and I would normally read
td.replace(microseconds=0) as an instruction to modify td in place.
Traditionally, such methods in python return None.
I agree with this objection. A method that is named “replace”, yet does
not modify the object, is badly named.

However, the existing ‘replace’ methods ‘datetime.date.replace’,
‘datetime.datetime.replace’, ‘datetime.time.replace’ already work this
way: they create a new value and return it, without modifying the
original object.

<URL:http://docs.python.org/3/library/datetime.html#datetime.date.replace>
<URL:http://docs.python.org/3/library/datetime.html#datetime.datetime.replace>
<URL:http://docs.python.org/3/library/datetime.html#datetime.time.replace>

So, if ‘datetime.timedelta.replace’ were to be implemented (I'm not
convinced it is needed), it should have that same behaviour.
--
\ “I tell you the truth: this generation will certainly not pass |
`\ away until all these things [the end of the world] have |
_o__) happened.” —Jesus Christ, c. 30 CE, as quoted in Matthew 24:34 |
Ben Finney
Steven D'Aprano
2014-01-31 03:53:27 UTC
Permalink
Post by Ben Finney
Post by Cameron Simpson
Hmm. I do not like the replace() as suggested.
Firstly, replace is a verb, and I would normally read
td.replace(microseconds=0) as an instruction to modify td in place.
Traditionally, such methods in python return None.
I agree with this objection. A method that is named “replace”, yet does
not modify the object, is badly named.
py> 'badly named'.replace('badly', 'well')
'well named'


"replace" is a perfectly reasonable name for a method which performs a
replacement, whether it replaces in place (for mutable objects) or makes
a copy with replacement (for immutable objects). What else would you call
it?

py> ('well named'.
... make_a_copy_while_simultaneously_performing_a_replacement_on_the_copy
... ('well', 'excessively long')
... )
'excessively long named'

While explicit is better than implicit, sometimes you can be *too*
explicit.


If timedelta objects were mutable, then I would expect that you would
just write the fields directly:

td.microseconds = 0

rather than mess about with a replace method.
--
Steven
Roy Smith
2014-01-31 03:58:10 UTC
Permalink
Post by Steven D'Aprano
"replace" is a perfectly reasonable name for a method which performs a
replacement, whether it replaces in place (for mutable objects) or makes
a copy with replacement (for immutable objects). What else would you call
it?
I suppose that by (imperfect) analogy to list.sort() and sorted(list),
it might make more sense to call it replaced(). But, it's too late for
any of that now. The other three classes in the module have replace(),
so that's the obvious name to use for the fourth class.
Ben Finney
2014-01-31 04:40:06 UTC
Permalink
Post by Ben Finney
Post by Cameron Simpson
Firstly, replace is a verb, and I would normally read
td.replace(microseconds=0) as an instruction to modify td in place.
Traditionally, such methods in python return None.
I agree with this objection. A method that is named “replace”, yet
does not modify the object, is badly named.
[…] What else would you call it?
I'd call it “substitute”, and keep thinking until I came up with
something better.

I wouldn't think very hard, though, because the existing usage of
‘foo.replace’ for a create-new-object-with-different-values method is
fairly well established in the Python built-in types and standard
library. Local expectations do, past some threshold, override general
expectations for the meaning of a term.
--
\ “Everyone is entitled to their own opinions, but they are not |
`\ entitled to their own facts.” —US Senator Pat Moynihan |
_o__) |
Ben Finney
Dan Sommers
2014-01-31 04:04:15 UTC
Permalink
Post by Ben Finney
However, the existing ‘replace’ methods ‘datetime.date.replace’,
‘datetime.datetime.replace’, ‘datetime.time.replace’ already work this
way: they create a new value and return it, without modifying the
original object.
That's how str.replace works, too.

*sigh*

Dan
Cameron Simpson
2014-01-31 02:01:40 UTC
Permalink
Post by Ben Finney
Post by Cameron Simpson
Hmm. I do not like the replace() as suggested.
Firstly, replace is a verb, and I would normally read
td.replace(microseconds=0) as an instruction to modify td in place.
Traditionally, such methods in python return None.
I agree with this objection. A method that is named “replace”, yet does
not modify the object, is badly named.
However, the existing ‘replace’ methods ‘datetime.date.replace’,
‘datetime.datetime.replace’, ‘datetime.time.replace’ already work this
way: they create a new value and return it, without modifying the
original object.
Ah.
--
Cameron Simpson <***@zip.com.au>

DRM: the functionality of refusing to function. - Richard Stallman
Loading...