A way to convert numbers to seconds - python

I know this is not the best way to explain what I want to achieve, but I will try to do it by defining my desired output.
The context: An object passes Point A at 6:58 (format is: minute:second) and passes Point B at 7:12. Calculate the time taken to get from Point A to B.
Logically, you'd take B time away from A time to get your result. I expected:
0.14 because it takes the object 14 seconds but got 0.54 because Python by default won't know that I need it to calculate in seconds format, where the 59 is maximum before you reach a new leading number.
My code is as simple as:
A=6.58
B=7.12
print(B-A)

Solution 1 : if you do not absolutely need float as inputs
from datetime import datetime, date, time
a = datetime.combine(date.today(), time(0, 6, 58))
b = datetime.combine(date.today(), time(0, 7, 12))
Solution 2 : if your inputs are floats
from datetime import datetime, date, time
def float_to_datetime(myfloat):
minutes, seconds = str(myfloat).split('.')
return datetime.combine(date.today(), time(0, int(minutes), int(seconds)))
a = float_to_datetime(6.58)
b = float_to_datetime(7.12)
In both cases, the output is:
print(b - a)
0:00:14
print((b-a).total_seconds())
14.0

Related

Why aren't identical datetimes equal?

I'm working on a simple Python3 script that considers data in five-minute increments. Thanks to this post, I have code which takes any Python datetime object and then rounds it down to the nearest five minutes. (:00, :05, :10, :15, etc.) Note that I cannot use pandas.
Now I need to be able to compare that "rounded-down" datetime with other datetimes, and here I'm running into a problem. Consider this test code:
import sys
from datetime import datetime
from datetime import timedelta
def roundDownDateTime(dt):
# Arguments:
# dt datetime object
delta = timedelta(minutes=1) * (dt.minute % 5)
return dt - delta
def testAlarm(testDate):
# Arguments:
# testDate datetime object
currDate = roundDownDateTime( datetime.now() ) # currDate is a DateTime object, rounded down to 5 mins
print("currDate: "+currDate.strftime("%Y%m%d%H%M"))
print("testDate: "+testDate.strftime("%Y%m%d%H%M"))
if(currDate == testDate):
print("ALARM!!!!")
def main():
testDate = datetime.strptime(sys.argv[1], "%Y%m%d%H%M")
testAlarm(testDate)
if __name__ == "__main__":
main()
The code does all of the following:
The main() function takes a string you enter on the command line,
then converts it into a "%Y%m%d%H%M" datetime
Your datetime is rounded down to the last five minute increment
In testAlarm(), your date is compared with the current date, also in
"%Y%m%d%H%M" format, also rounded down five minutes.
If the current date matches the cmd line argument, you should get an
"ALARM!!! in the output.
Here's the actual output, run on my Ubuntu machine:
me#unbuntu1$ date
Tue Jan 17 14:27:41 UTC 2023
me#unbuntu1$
me#unbuntu1$ python3 toy04.py 202301171425
currDate: 202301171425
testDate: 202301171425
me#unbuntu1$
Okay: Although I'm rounding down my date to match the "rounded-down" version of the current date, the if(currDate == testDate): line of code is still evaluating to False. While both datetimes appear equal in the "%Y%m%d%H%M" format, they are somehow not equal.
My first thought was that maybe the "rounded down" datetime still retained some residual seconds or microseconds even after the rounding part? So I modified my function to this:
def roundDownDateTime(dt):
# Arguments:
# dt DateTime object
delta = timedelta(minutes=1) * (dt.minute % 5)
dt = dt - delta
dt.replace(second=0, microsecond=0)
return dt
But that makes no difference; I still get the exact same output as before.
Normally, you would only care if currDate > testDate for alarming purposes. But in my case, I must be able to compare datetimes for equality after one (or more) of them has been through the roundDownDateTime() function. What am I missing? Is my roundDownDateTime() function faulty? Thank you.
dt.replace returns a new datetime object; it does not modify dt in place.
def roundDownDateTime(dt):
# Arguments:
# dt DateTime object
delta = timedelta(minutes=1) * (dt.minute % 5)
dt = dt - delta
return dt.replace(second=0, microsecond=0)

how to convert datetime-like string into milliseconds

I have a user-defined function (return_times) that takes json file and returns two datetime-like strings.
time_1, time_2= return_times("file.json")
print(time_1, time_2) # outputs: 00:00:11.352 00:01:51.936
By datetime-like string I mean 00:00:11.352 which suits '%H:%M:%S.%f' formatting. However, when I try to convert them into milliseconds, I get negative values.
from datetime import datetime
dt_obj_1 = datetime.strptime(time_1, '%H:%M:%S.%f')
start_ms = dt_obj_1.timestamp() * 1000
dt_obj_2 = datetime.strptime(time_2, '%H:%M:%S.%f')
end_ms = dt_obj_2.timestamp() * 1000
print(start_ms, end_ms ) # outputs: -2209019260648.0 -2209019160064.0
If I success I would like to trim a video with the following command:
from moviepy.video.io.ffmpeg_tools import ffmpeg_extract_subclip
ffmpeg_extract_subclip("long_video.mp4", start_ms, end_ms, targetname="video_trimmed.mp4"), so just delete ` * 1000` part.
Note that ffmpeg_extract_subclip requires its t1 and t2 parameters to be in seconds, not in milliseconds as I initially thought.
Because of those negative integers I am not able to successfully run the trimming process.
I searched the web that mainly discusses several formats for the year, month and day, but not '%H:%M:%S.%f'.
What may I be overlooking?
What may I be overlooking?
time.strptime docs
The default values used to fill in any missing data when more accurate
values cannot be inferred are (1900, 1, 1, 0, 0, 0, 0, 1, -1).
whilst start of epoch is 1970. You might get what you want by computing delta between what you parsed and default strptime as follows:
import datetime
time1 = "00:00:11.352"
delta = datetime.datetime.strptime(time1, "%H:%M:%S.%f") - datetime.datetime.strptime("", "")
time_s = delta.total_seconds()
print(time_s)
output
11.352
You need to add the year date (year, month, day) to datetime, else this will default to 1 January 1900.
What you do is this:
from datetime import datetime
s = "00:00:11.352"
f = '%H:%M:%S.%f'
datetime.strptime(s, f) # datetime.datetime(1900, 1, 1, 0, 0, 11, 352000)
One way to do this is to append the date-string to the time-string you receive from return_times
From https://stackoverflow.com/a/59200108/2681662
The year 1900 was before the beginning of the UNIX epoch, which
was in 1970, so the number of seconds returned by timestamp must be
negative.
What to do?
It's better to use a time object instead of a datetime object.
from datetime import time
time_1 = "00:00:11.352"
hours, minutes, seconds = time_1.split(":")
print(time(hour=int(hours), minute=int(minutes), second=int(float(seconds)),
microsecond=int(float(seconds) % 1 * 1000000)))
You can split the time string into hours, minutes, seconds and miliseconds and with some simple math calculations, you get the whole time in miliseconds

Python Datetime Time Difference gives -999999999 in min when dif is small

In my small script I wanted to give script task time. In small time like under 1 min, I give min as -999999999.
But there is no problem in others. Seconds and microseconds can be got and they are int type, though min <class 'datetime.timedelta'>
My related code bunch is:
from datetime import datetime,timedelta
now = datetime.now()
# some code here
then = datetime.now()
delta= then-now
print(delta.seconds) # 10
print(delta.microseconds) # 432214
print(delta.min) # '-999999999 days, 0:00:00'
In the console I give:
datetime.timedelta(days=-999999999)
Where am I doing wrong?
Only days, seconds and microseconds are stored internally in a timedelta objects
The min attribute that you are accessing does not represent minutes and is actually the most negative timedelta object, timedelta(-999999999)
You can get the value of minutes using the total_seconds method from the timedelta object:
minutes = delta.total_seconds() / 60
Read documentation about min attribute here
timedelta.min doesn't give you minutes, but according to the documentation the smallest possible delta value.
timedelta.min
The most negative timedelta object, timedelta(-999999999).

How to get a period of time with Numpy?

If a np.datetime64 type data is given, how to get a period of time around the time?
For example, if np.datetime64('2020-04-01T21:32') is given to a function, I want the function to return np.datetime64('2020-04-01T21:30') and np.datetime64('2020-04-01T21:39') - 10 minutes around the given time.
Is there any way to do this with numpy?
Numpy does not have a built in time period like Pandas does.
If all you want are two time stamps the following function should work.
def ten_minutes_around(t):
t = ((t.astype('<M8[m]') # Truncate time to integer minute representation
.astype('int') # Convert to integer representation
// 10) * 10 # Remove any sub 10 minute minutes
).astype('<M8[m]') # convert back to minute timestamp
return np.array([t, t + np.timedelta64(10, 'm')]).T
For example:
for t in [np.datetime64('2020-04-01T21:32'), np.datetime64('2052-02-03T13:56:03.172')]:
s, e = ten_minutes_around(t)
print(s, t, e)
gives:
2020-04-01T21:30 2020-04-01T21:32 2020-04-01T21:40
2652-02-03T13:50 2652-02-03T13:56:03.172 2652-02-03T14:00
and
ten_minutes_around(np.array([
np.datetime64('2020-04-01T21:32'),
np.datetime64('2652-02-03T13:56:03.172'),
np.datetime64('1970-04-01'),
]))
gives
array([['2020-04-01T21:30', '2020-04-01T21:40'],
['2652-02-03T13:50', '2652-02-03T14:00'],
['1970-04-01T00:00', '1970-04-01T00:10']], dtype='datetime64[m]')
To do so we can get the minute from the given time and subtract it from the given time to get the starting of the period and add 9 minutes to get the ending time of the period.
import numpy as np
time = '2020-04-01T21:32'
dt = np.datetime64(time)
base = (dt.tolist().time().minute) % 10 // base would be 3 in this case
start = dt - np.timedelta64(base,'m')
end = start + np.timedelta64(9,'m')
print(start,end,sep='\n')
I hope this helps.

Python fraction of seconds

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.

Categories