To convert the amount of milliseconds represented by a string I created the following function:
time_str = '1:16.435'
def milli(time_str):
m, s = time_str.split(':')
return int(int(m) * 60000 + float(s) * 1000)
milli(time_str)
But I'm wondering if there is a native Python function to do this directly.
You can easily make it longer and more complicated with datetime:
import datetime
dateobj=datetime.datetime.strptime("1:16.435","%M:%S.%f")
timeobj=dateobj.time()
print(timeobj.minute*60000+timeobj.second*1000+timeobj.microsecond/1000)
76435.0
Now you have 2 additions, 2 multiplications, and even a division. And the bonus points for loading a package, of course. I like your original code more.
Since you're looking for functions to do this for you, you can take advantage of TimeDelta object which has .total_seconds(). This way you don't have to do that calculation. Just create your datetime objects then subtract them:
from datetime import datetime
datetime_obj = datetime.strptime("1:16.435", "%M:%S.%f")
start_time = datetime(1900, 1, 1)
print((datetime_obj - start_time).total_seconds() * 1000)
output:
76435.0
The reason for choosing datetime(1900, 1, 1) is that when you use strptime with that format it fills the rest to make this form: 1900-01-01 00:01:16.435000.
If your string changes to have Hour for example, you just need to change your format and it works as expected. No need to change your formula and add another calculation:
datetime.strptime("1:1:16.435", "%H:%M:%S.%f")
start_time = datetime(1900, 1, 1)
print((datetime_obj - start_time).total_seconds() * 1000)
Related
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
I want to convert timestamps to dates and truncate minute and seconds,then, convert it back to timestamps. I know I can do that with some mathematical algorithm like timestamps/60 or timestamps/3600, but I want to use Python provided functions. My code is like below. I tried two methods:
for timeStamp in lineTimeStamps:
#first try
day1=datetime.datetime.\
fromtimestamp(float(timeStamp)).strftime("%Y-%m-%d %H")
timestamp1 = time.mktime(day1)
#second try
day2=datetime.datetime.\
fromtimestamp(float(timeStamp)).\
replace( minute=0, second=0, microsecond=0).timetuple()
timestamp2 = time.mktime(day2)
In timestamp1 = time.mktime(day1), I got the error like:
TypeError: Tuple or struct_time argument required
In timestamp2 = time.mktime(day2), I got the error like:
OverflowError: mktime argument out of range
How can I convert it back to timestamps?
Converting to string and back is very slow operation. I'd suggest to use that math algorithm anyway:
# get integer and fractional parts of modulo division
i, f = divmod(timeStamp, 3600)
# i * 3600 is hour:0:0 time
timestamp1 = i * 3600
And that's it.
strftime("%Y-%m-%d %H") returns a string.
If you want to go down this path, you should call strptime to turn it back into a time object:
day1=datetime.datetime.\
fromtimestamp(float(timeStamp)).strftime("%Y-%m-%d %H")
day1 = time.strptime(day1, "%Y-%m-%d %H")
timestamp1 = time.mktime(day1)
I would recommend #baldr approach though...
I have a problem that seems really easy but I can't figure it out.
I want to achieve the following:
Time_as_string - time_now = minutes left until time as string.
I scrape a time from a website as a string, for example: '15:30'.
I want to subtract the current time from this to show how many minutes
are left untill the scraped time string.
I tried many things like strftime(), converting to unix timestamp, googling solutions etc.
I can make a time object from the string through strftime() but I can't subtract it from the current time.
What is the best way to achieve this?
from datetime import datetime
s = "15:30"
t1 = datetime.strptime(s,"%H:%M")
diff = t1 - datetime.strptime(datetime.now().strftime("%H:%M"),"%H:%M")
print(diff.total_seconds() / 60)
94.0
If '15:30' belongs to today:
#!/usr/bin/env python3
from datetime import datetime, timedelta
now = datetime.now()
then = datetime.combine(now, datetime.strptime('15:30', '%H:%M').time())
minutes = (then - now) // timedelta(minutes=1)
If there could be midnight between now and then i.e., if then is tomorrow; you could consider a negative difference (if then appears to be in the past relative to now) to be an indicator of that:
while then < now:
then += timedelta(days=1)
minutes = (then - now) // timedelta(minutes=1)
On older Python version, (then - now) // timedelta(minutes=1) doesn't work and you could use (then - now).total_seconds() // 60 instead.
The code assumes that the utc offset for the local timezone is the same now and then. See more details on how to find the difference in the presence of different utc offsets in this answer.
The easiest way is probably to subtract two datetimes from each other and use total_seconds():
>>> d1 = datetime.datetime(2000, 1, 1, 20, 00)
>>> d2 = datetime.datetime(2000, 1, 1, 16, 30)
>>> (d1 - d2).total_seconds()
12600.0
Note that this won't work if the times are in different timezones (I just picked January 1, 2000 to make it a datetime). Otherwise, construct two datetimes in the same timezones (or UTC), subtract those and use total_seconds() again to get the difference (time left) in seconds.
I need to convert to convert an integer into a datetime.time instance. I get the time in elapsed seconds so it may well be larger than 59.
I know that I can create a time object by using:
import datetime
def to_time(seconds):
hours = seconds / 3600
mins = (seconds%3600)/60
sec = (seconds%3600)%60
return datetime.time(hours,mins,sec)
and I could hand this over to a mapping function if a have list of timevalues to convert. But I think it is ugly. Isn't there a better way to do so?
Actually, the problem is a bit more complex. I get a floating point as time where datetime.date.fromordinal(int(time)) returns the date and to_time(time - int(time)*86400) would return the time. I can than combine them to my datetime-object. So the input would be for example 734869.00138889, which should result in 2013-01-01 00:02
I would definitely prefer a less crowded method.
The simplest method is to use a datetime.timedelta() object with your time value as the days argument, and add that to datetime.datetime.min; that'll be off by one day so you have to subtract 1 from the value:
from datetime import datetime, timedelta
dt = datetime.min + timedelta(days=time - 1)
This avoids having to cast the value to an integer for the ordinal, then just the fraction for the time portion.
Demo:
>>> from datetime import datetime, timedelta
>>> t = 734869.00138889
>>> datetime.min + timedelta(days=t - 1)
datetime.datetime(2013, 1, 1, 0, 2, 0, 93)
Not sure if I understood how to convert the number after the decimal point to seconds, but I would try something along this line:
def to_datetime(time):
return datetime.datetime.fromordinal(int(time)) + \
datetime.timedelta(time % 1)
[update]
Is this the result you want?
>>> to_datetime(734869.00138889)
datetime.datetime(2013, 1, 1, 0, 2, 0, 93)
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.