<div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr"><div dir="ltr">This thread petered out, seemingly with a consensus that we should update the docs -- is anyone doing that?<div><br></div><div>But anyway, I'd like to offer a counterpoint:</div><div><br></div><div>From the OP, it is clear that:</div><div><br></div><div>* Folks have a need for timedeltas to be converted to numbers values, with units other than seconds (milliseconds, at least).</div><div>* If left to their own devices, they may well do it wrong (Or at least not as right as they should.</div><div><br></div><div>So: it would be good to provide a correct, simple,  intuitive, and discoverable way to do that.</div><div><br></div><div><font face="monospace, monospace">timedelta.total_seconds()</font></div><div><br></div><div>Provides that for seconds, but there is no equivalent for other units.</div><div><br></div><div><font face="monospace, monospace">a_time_delta / timedelta(microseconds=1)</font></div><div><br></div><div>Is now possible in py3, and has been proposed as the canonical way to convert to specific time units.</div><div><br></div><div>However, while it does provide a correct[1] way to do it, it is:</div><div><br></div><div>- not very simple</div><div>- not very intuitive.<br></div><div><div>- not the least bit discoverable</div><br class="gmail-Apple-interchange-newline"></div><div>Each of these in turn:</div><div><br></div><div>simple:</div><div>=====</div><div><br></div><div>compare</div><div><font face="monospace, monospace"><br></font></div><div><font face="monospace, monospace">duration = a_timedelta.total_seconds()</font></div><div><br></div><div>to</div><div><font face="monospace, monospace"><br></font></div><div><span style="font-family:monospace,monospace">duration =</span><span style="font-family:monospace,monospace"> </span><font face="monospace, monospace">a_timedelta / datetime.timedelta(seconds=1)</font></div><div><br></div><div>Keep in mind that the timedelta object may have been generated by another module somehow, so the coder that gets it and wants to turn it into a number of seconds (or milliseconds, or ...) needs to import datetime and reference the timedelta object. And if they are converting to a plain number, it's probably because they don't want to be working with timedeltas at all anyway. So no, not so simple.</div><div><br></div><div>intuitive:</div><div>======</div><div><br></div><div>A casual user reading the first will very likely know what it means -- a  casual user reading the second line will need to think about it carefully, and probably have to go read the datetime docs, or at least do some experiments to make sure it does what they think it does. Granted, a comment:</div><div><br></div><div><span style="font-family:monospace,monospace">duration =</span><span style="font-family:monospace,monospace"> </span><span style="font-family:monospace,monospace">a_timedelta / datetime.timedelta(seconds=1)  # convert to seconds</span><br></div><div><br></div><div>would help a lot, but if you need a comment to explain a line of code this simple, then it's not intuitive.</div><div><br></div><div>A couple more data points:</div><div><br></div><div>-- I am a physical scientist, I work with unitted quantities all the time (both in code and in other contexts). It never dawned on me to use this approach to convert to seconds or milliseconds, or ... Granted, I still rely on python2 for a fair bit of my work, but still, I had to scratch my head when it was proposed on this thread.</div><div><br></div><div>-- There are a number of physical unit libraries in Python, and as far as I know, none of them let you do this to create a unitless value in a particular unit. "pint" for example:</div><div><br></div><div><a href="https://pint.readthedocs.io/en/latest/">https://pint.readthedocs.io/en/latest/</a><br></div><br>In pint, you can create objects with units, including time:<br><br><font face="monospace, monospace">In [50]: timespan = 2 * ureg.day                                                <br>In [51]: print(timespan)                                                        <br>2 day</font><br><br>But if you divide a value of days by a value in seconds, you don't get a unitless seconds per day:</div><div dir="ltr"><br><div dir="ltr"><font face="monospace, monospace">In [54]: unitless = timespan / (1 * ureg.second)                                </font></div><div dir="ltr"><font face="monospace, monospace">In [55]: print(unitless)                                                        <br></font></div><div dir="ltr"><font face="monospace, monospace">2.0 day / second</font></div><div dir="ltr"><br></div><div>Though pint does know it is dimensionless:</div><div dir="ltr"><br></div><div dir="ltr"><font face="monospace, monospace">In [56]: unitless.dimensionless                                                 </font></div><div dir="ltr"><font face="monospace, monospace">Out[56]: True</font></div><div dir="ltr"><br></div><div>And you can reduce it to a dimensionless object:</div><div><br></div><div dir="ltr"><font face="monospace, monospace">In [57]: unitless.to_reduced_units()                                            </font></div><div dir="ltr"><font face="monospace, monospace">Out[57]: 172800.0 <Unit('dimensionless')></font></div><div dir="ltr"><br></div>And there is your seconds value.</div><div dir="ltr"><br></div><div dir="ltr">But the "right" way to get a given pint object of time into particular units is to convert, and then, if you want a plain number, get the magnitude:<br><br><font face="monospace, monospace">In [53]: print(<a href="http://timespan.to">timespan.to</a>('second').magnitude)       </font>                          <font face="monospace, monospace"><br>172800.0</font><br><br>So no -- dividing a datetime by another datetime with the value you want is not intuitive: not to a physical scientist, not to a user of other physical quantities libraries -- is it intuitive to anyone other than someone that was involved in python datetime development??</div><div dir="ltr"><br></div><div>Discoverable:</div><div>==========</div><div dir="ltr"><br></div><div>It is clearly not discoverable -- the OP didn't find it, and no one other than Alexander found it on this thread (I'm pretty sure). That could be made much better with docs, but we all know no one reads docs -- I'm willing to bet that even if we better document it, folks will still be writing utility functions like the OP posted.</div><div><br></div><div>And  (this is also a doc issue) -- I wanted to know what the options were for units we could specify to the datetime constructor, so I used the nifty iPython ?, and got:</div><font face="monospace, monospace"><div dir="ltr"><font face="monospace, monospace"><br></font></div>In [59]: timedelta?                                                             <br>Init signature: timedelta(self, /, *args, **kwargs)<br>Docstring:      Difference between two datetime values.<br><br></font><div><br></div><div>Gosh, that's helpful! (we really need to fix that regardless of this thread). And someone earlier mentioned "weeks" without realizing that is was already supported:</div><div><br></div><div><div><font face="monospace, monospace">In [60]: timedelta(weeks=1)                                                     </font></div><div><font face="monospace, monospace">Out[60]: datetime.timedelta(days=7)</font></div></div><div dir="ltr"><br><div>So we have a real discoverability problem -- we really need to fix that.</div><div><br></div><div>On the other hand, if we add a few convenience methods, we will have a way for folks to do this that is:</div><div><br></div><div>correct</div><div>simple</div><div>intuitive</div><div>discoverable</div><div><br></div><div>And we really don't need to add many. Looking at the docs ('cause the docstring is useless), I see that the timedelta takes:</div><div><br></div><font face="monospace, monospace">datetime.timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)</font><div><br></div><div>So at most, we could have:</div><div><br></div><div><font face="monospace, monospace">.total_microseconds()</font></div><div><div><font face="monospace, monospace">.total_seconds()</font></div><div><font face="monospace, monospace">.total_minutes()</font></div><div><font face="monospace, monospace">.total_hours()</font></div><div><font face="monospace, monospace">.total_days()</font></div><div><font face="monospace, monospace">.total_weeks()</font></div><br class="gmail-Apple-interchange-newline"></div><div>Yes, I know that that's more code to write, maintain and document, but really, it will not take long to write, will take less work to document than the doc improvements we need anyway, and hardly any extra maintenance burden.</div><div><br></div><div>(and the utility of weeks and minutes is questionable)</div><div><br></div><div>BTW, why are these methods, rather than properties?</div><div><br></div><div>Another option, is, of course, to add a:</div><div><br></div><div>.to_unit() method that takes the above as strings. -- but unless we ar going to support a bunch more units than those six, I'd rather see the methods. And what would those others be? fortnights? </div><div><br></div><div>I've made my case -- and maybe we won't do this. But let's please at least update the docstring of timedleta!</div><div><br></div><div>-CHB</div><div><br></div><div><br></div><div>[1] is it the best possible for microseconds? it returns a float, which can only carry 15 or so digits, which is "only" 300 or so years. So microsecond precision is lost for timedeltas representing longer than that -- does that matter ???</div><div><br></div><div><br></div></div></div></div></div></div>-- <br><div dir="ltr" class="gmail_signature"><br>Christopher Barker, Ph.D.<br>Oceanographer<br><br>Emergency Response Division<br>NOAA/NOS/OR&R            (206) 526-6959   voice<br>7600 Sand Point Way NE   (206) 526-6329   fax<br>Seattle, WA  98115       (206) 526-6317   main reception<br><br><a href="mailto:Chris.Barker@noaa.gov" target="_blank">Chris.Barker@noaa.gov</a></div></div>