Python fraction of seconds - python

What is the best way to handle portions of a second in Python? The datetime library is excellent, but as far as I can tell it cannot handle any unit less than a second.

In the datetime module, the datetime, time, and timedelta classes all have the smallest resolution of microseconds:
>>> from datetime import datetime, timedelta
>>> now = datetime.now()
>>> now
datetime.datetime(2009, 12, 4, 23, 3, 27, 343000)
>>> now.microsecond
343000
if you want to display a datetime with fractional seconds, just insert a decimal point and strip trailing zeros:
>>> now.strftime("%Y-%m-%d %H:%M:%S.%f").rstrip('0')
'2009-12-04 23:03:27.343'
the datetime and time classes only accept integer input and hours, minutes and seconds must be between 0 to 59 and microseconds must be between 0 and 999999. The timedelta class, however, will accept floating point values with fractions and do all the proper modulo arithmetic for you:
>>> span = timedelta(seconds=3662.567)
>>> span
datetime.timedelta(0, 3662, 567000)
The basic components of timedelta are day, second and microsecond (0, 3662, 567000 above), but the constructor will also accept milliseconds, hours and weeks. All inputs may be integers or floats (positive or negative). All arguments are converted to the base units and then normalized so that 0 <= seconds < 60 and 0 <= microseconds < 1000000.
You can add or subtract the span to a datetime or time instance or to another span. Fool around with it, you can probably easily come up with some functions or classes to do exaxtly what you want. You could probably do all your date/time processing using timedelta instances relative to some fixed datetime, say basetime = datetime(2000,1,1,0,0,0), then convert to a datetime or time instance for display or storage.

A different, non mentioned approach which I like:
from datetime import datetime
from time import sleep
t0 = datetime.now()
sleep(3)
t1 = datetime.now()
tdelta = t1 - t0
print(tdelta.total_seconds())
# will print something near (but not exactly 3)
# 3.0067

To get a better answer you'll need to specify your question further, but this should show at least how datetime can handle microseconds:
>>> from datetime import datetime
>>> t=datetime.now()
>>> t.microsecond
519943

NumPy 1.4 (in release candidate stage) has support for its own Date and DateArray objects. The one advantage is that it supports frequencies smaller than femtoseconds: http://projects.scipy.org/numpy/browser/trunk/doc/neps/datetime-proposal.rst
Otherwise I would go with the regular datetime subsecond frequencies.

Related

how to convert datetime object to time_ns

I have the following problem I need to convert some datetime object to time_ns (present in time)
all I can find is to convert the now datetime to that fixed nanoseconds number (i understand that it is calculated from a fixed date in 1970)
import time
now = time.time_ns()
all I want is to convert some normal datetime object to that fixed nanoseconds number
from datetime import datetime
x = datetime(2022, 2, 22, 15, 41, 50)
i don't want to be restricted to only now dates. is there some function in the library that does that? for the moment i cannot find anything
thank you very much
Since python 3.3 datetime has a timestamp function. Make sure to replace the timezone, otherwise local timezone will being taken and if you want to have nanosecond number you can multiply the seconds number.
from datetime import datetime;
print(datetime(2022,2,22,15,41,50).replace(tzinfo=timezone.utc).timestamp()*10**9)

Python: How to convert string time to decimal seconds?

String Time
00:51:21,920
Decimal Time
3,081.92 (second)
Is there anyway that can convert between string time and decimal time in seconds? I want to use it in moviepy VideoFileClip.subclip.
Below is what I have done and it works. But I assume there should be an easier way like a function in a library.
def TrsTime(VideoTime):
return (datetime.strptime(VideoTime, '%H:%M:%S,%f').hour*60*60+
datetime.strptime(VideoTime, '%H:%M:%S,%f').minute*60+
datetime.strptime(VideoTime, '%H:%M:%S,%f').second+
datetime.strptime(VideoTime, '%H:%M:%S,%f').microsecond/1000/1000)
Yes, there is a simpler way:
from datetime import datetime as dt
(dt.strptime(VideoTime, '%H:%M:%S,%f') - dt(1900, 1, 1)).total_seconds()
>>> 3081.92
This works on the principal that the timedelta object has a .total_seconds() function. So by subtracting your time (whose year, month, day defaults to 1 Jan 1900) from 1 Jan 1900, you get the delta in seconds.

Surprising behaviour of Python date and timedelta subtraction

I am trying to do some Python date and timedelta maths and stumbled upon this.
>>> import datetime
>>> dt = datetime.date(2000, 4, 20)
>>> td = datetime.timedelta(days=1)
>>> dt - td
datetime.date(2000, 4, 19)
>>> -(td) + dt
datetime.date(2000, 4, 19)
>>> dt - td == dt + (-td)
True
So far so good, but when the timedelta also includes some hours it gets interesting.
>>> td = datetime.timedelta(days=1, hours=1)
>>> dt - td
datetime.date(2000, 4, 19)
>>> -(td) + dt
datetime.date(2000, 4, 18)
or in a comparison:
>>> dt - td == dt + (-td)
False
I would have expected that a - b == a + (-b), but this doesn't seem to work for date and timedelta. As far as I was able to track that down, this happens because adding/subtracting date and timedelta only considers the days field of timedelta, which is probably correct. However negating a timedelta considers all fields and may change the days field as well.
>>> -datetime.timedelta(days=1)
datetime.timedelta(-1)
>>> -datetime.timedelta(days=1, hours=1)
datetime.timedelta(-2, 82800)
As can be seen in the second example, days=-2 after the negation, and therefore date + timedelta will actually subtract 2 days.
Should this be considered a bug in the python datetime module? Or is this rather some 'normal' behaviour which needs to be taken into account when doing things like that?
Internally the datetime module creates a new timedelta, with just the days field of the original timedelta object passed in, when subtracting a timedelta to a date object. Which equates to following, code that seems to be quite odd.
>>> dt + datetime.timedelta(-(-(-dt).days))
datetime.date(2000, 4, 18)
I can't really sea a reason for just using the negated days field when doing date - timedelta subtractions.
Edit:
Here is the relevant code path in python datetime module:
class date:
...
def __sub__(self, other):
"""Subtract two dates, or a date and a timedelta."""
if isinstance(other, timedelta):
return self + timedelta(-other.days)
...
If it would just pass on -other then the condition a - b == a + (-b) would hold true. (It would change current behaviour though).
class date:
...
def __sub__(self, other):
"""Subtract two dates, or a date and a timedelta."""
if isinstance(other, timedelta):
return self - other # timedelta.__rsub__ would take care of negating other
...
Should this be considered a bug in the python datetime module? Or is
this rather some 'normal' behaviour which needs to be taken into
account when doing things like that?
No, this should not be considered a bug. A date does not track its state in terms of hours, minutes, and seconds, which is what would be needed for it to behave in the way you suggest it ought to.
I would consider the code you've presented to be a bug: the programmer is using the wrong datatype for the work they're trying to accomplish. If you want to keep track of time in days, hours, minutes and seconds, then you need a datetime object. (which will happily provide you with a date once you've done all of the arithmetic you care to do)
This is because of the way how negative timedeltas are represented.
import datetime
td = datetime.timedelta(days=1, hours=1)
print (td.days, td.seconds)
# prints 1 3600
minus_td = -td
print (minus_td.days, minus_td.seconds)
# prints -2 82800
I hope you now better understand why days were affected.
Seconds in a timedelta are always normalized to a positive amount between 0 and 86399:
>>> print (datetime.timedelta(seconds=-10).seconds)
86390

Turn number representing total minutes into a datetime object in python

If I have a number representing a period I am interested in, for example the number 360 representing 360 minutes or 6 hours, how do I turn this into a datetime object such that I can perform the standard datetime object functions on it?
Similarly, if I have a datetime object in the format 00:30:00, representing 30 minutes, how do I turn that into a normal integer variable?
import datetime
t = datetime.timedelta(minutes=360)
This will create an object, t, that you can use with other datetime objects.
To answer the 2nd question you just edited in, you can use t.total_seconds() to return whatever your timedelta holds back into an integer in seconds. You'll have to do the conversion to minutes or hours manually though.
You may want to look at time deltas:
delta = datetime.timedelta(minutes=360)
If your time data is in '00:30:00' format then you should use strptime
>>> from datetime import datetime
>>> time = '00:30:00'
>>> datetime.strptime(time, '%H:%M:%S).time()
datetime.time(0, 30)
If your data is in 30 (integer) format
>>> from datetime import datetime, timedelta
>>> from time import strftime, gmtime
>>> minutes = timedelta(minutes=360)
>>> time = strftime('%H:%M:%S', gmtime(minutes.total_seconds()))
>>> datetime.strptime(time, '%H:%M:%S').time()
datetime.time(6, 0)

Override operator + to make date + time = datetime in Python

I have a couple classes extending builtin datetime.*
Is there any good reason to not overload + (MyTime.__radd___) so MyDate + MyTime returns a MyDateTime?
This is already implemented as a class method, datetime.datetime.combine:
import datetime
d = datetime.date(2010, 12, 5)
t = datetime.time(10, 22, 15)
dt = datetime.datetime.combine(d, t)
print dt
prints
2010-12-05 10:22:15
This would generally be frowned upon because you're really combining rather than adding; this is why the actual datetime library has a combine method rather than using addition in this way.
I'm not aware of any other cases in Python where <instance of TypeA> + <instance of TypeB> produces <instance of TypeC>. Thus, the Principle of least astonishment suggests that you should simply provide a combine method rather than overload addition.
Yes, there is at least one good reason not to: the resulting instance is completely different from the two input instances. Is this important? I don't think so -- consider that date - date yields timedelta.
The way I see it:
Does adding two dates together make sense? No.
Does adding two times together make sense? No.
Does adding a date and a time together make sense? Yup!
Does adding a date and a timedelta togethor make sense? Maybe.
Does adding a time and a timedelta together make sense? Maybe.
and for subtraction
Does subtracting two dates make sense? Yes.
Does subtracting two times make sense? Yes.
Does subtracting a time from a date make sense? Nope.
Does subtracting a timedelta from a date make sense? Maybe.
Does subtracting a timedelta from a time make sense? Maybe.
Developing along the lines of what makes sense:
date + time => datetime
date + timedelta => date | datetime or exception or silently drop time portion
time + date => datetime
time + timedelta => time | wrap-around or exception
date - date => timedelta
date - timedelta => date | datetime or exception or silently drop time portion
time - time => timedelta
time - timedelta => time | wrap-around or exception
datetime + timedelta => datetime
datetime - timedelta => datetime
So, if it were me and I were designing a Date, Time, DateTime, TimeDelta framework, I would allow:
date + time
date - date
time - time
datetime + timedelta
datetime - timedelta
and for these:
date +/- timedelta
time +/- timedelta
I would default to returning the same type if the timedelta had none of the other type, and raising an exception if the timedelta did have some of the other type, but there would be a setting that would control that. The other possible behavior would be to drop the unneeded portion -- so a date combined with a timedelta that had hours would drop the hours and return a date.
Due to the existence of the date, time, and datetime cross-type addition and subtraction operators, I would think that this is fine, so long as it is well defined.
Currently (2.7.2):
date = date + timedelta
date = date - timedelta
timedelta = date - date
datetime = datetime + timedelta
datetime = datetime - timedelta
timedelta = datetime - datetime
I believe the following is also reasonable for an extension:
timedelta = time - time
datetime = date + time
I was going to suggest the following as well, but time has very specific min and max values for hour, minute, second, and microsecond, thus requiring a silent wraparound of values or returning of a different type:
time = time + timedelta
time = time - timedelta
Similarly, date cannot handle a timedelta of less than a day being added to it. Often I have been told to simply use Duck Typing with Python, because that's the intent. If that is true, then I would propose the following completed interface:
[date|datetime] = date + timedelta
[date|datetime] = date - timedelta
timedelta = date - date
[time|timedelta] = time + timedelta
[time|timedelta] = time - timedelta
timedelta = time - time
datetime = datetime + timedelta
datetime = datetime - timedelta
datetime = date + time
datetime = date - time
timedelta = datetime - datetime
timedelta = datetime - date
timedelta = timedelta + timedelta
timedelta = timedelta - timedelta
In which, given the case that date has precision loss (for timedelta's with partial days), it is promoted to datetime. Similarly, given the case that time has precision loss (for timedelta's that yield a result of more than one day, or negative time), it is promoted to timedelta. However, I'm not fully comfortable with [time|timedelta]. It makes sense given the rest of the interface from parallelism and precision views, but I do think it might be more elegant to just wraparound the time to the proper hour, thus changing all the [time|timedelta]'s to simply time, but unfortunately that leaves us with lost precision.
In my opinion, the most valuable uses of operator overloading are situations where many input values can be combined. You'd never want to deal with:
concat(concat(concat("Hello", ", "), concat("World", "!")), '\n');
or
distance = sqrt(add(add(x*x, y*y), z*z));
So we overload math symbols to create a more intuitive syntax. Another way to deal with this problem is variadic functions, like + in Scheme.
With your date + time = datetime, it doesn't make sense to add datetime + datetime, datetime + time, or datetime + date, so you could never encounter a situation like those above.
In my opinion, once again, the right thing is to use a constructor method. In a language with strong typing like C++, you'd have DateTime(const Date &d, const Time &t). With Python's dynamic typing, I guess they gave the function a name, datetime.combine(date, time), to make the code clearer when the types of the input variables are not visible in the code.
I guess most important things are functionality and efficiency. Of course using a simple + operator will be easier to use, but i am not sure about functionality.
If we compare it to datetime.combine, What combine do is:
dt = date(2011,01,01)
tm = time(20,00)
dtm = datetime.combine(dt, tm)
For dtm
If dt is a date object and tm is a time object, than date info is taken from dt, time info and tzinfo is taken from tm object
if dt is a datetime object, than its time and tzinfo attributes will be ignored.
From that point of view, working with datetime objects do not seem to be simple objects, but more compex structures with diffrent attributes, like timezone info.
Probably thats why datetime objects have some additional functions that is used for formatting object type and data structure of the object.
Python have a motto (something like that):
In python, nothing is unchangable, if you know what you are doing. If not, it is better to leave library functions as they are...
So, in my opinion, it is better you use combine that overloading + operator

Categories