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
Related
Trying to write a test to see if my datetime conversions are working appropriately and getting some unexpected results.
import pytz
from datetime import datetime
def format_datetime(dt):
if not dt.tzinfo:
raise pytz.UnknownTimeZoneError('timezone not set')
time = dt.astimezone(pytz.utc).strftime('%Y-%m-%dT%H:%M:%S')
millis = dt.microsecond / 1000
string = '{}{}'.format(time, '.%03dZ' % millis)
return string
dt = datetime(2019, 3, 20, 1, 1, 1, 1)
# test 1
utc_dt = dt.replace(tzinfo=pytz.utc)
pdt_dt = dt.replace(tzinfo=pytz.timezone('America/Los_Angeles'))
print(format_datetime(utc_dt)) # 2019-03-20T01:01:01.000Z
print(format_datetime(pdt_dt)) # 2019-03-20T08:54:01.000Z
# test 2
utc_dt2 = dt.replace(tzinfo=pytz.utc)
pdt_dt2 = utc_dt2.astimezone(pytz.timezone('America/Los_Angeles'))
print(format_datetime(utc_dt2)) # 2019-03-20T01:01:01.000Z
print(format_datetime(pdt_dt2)) # 2019-03-20T01:01:01.000Z
I don't understand why, in the first test print(format_datetime(pdt_dt)) changes the minutes value, but in the second test the minutes aren't changed. (I understand why the hours are different between the two examples).
You can't just assign a pytz timezone to a datetime, you must use localize or astimezone:
utc_dt = pytz.utc.localize(dt)
pdt_dt = utc_dt.astimezone(pytz.timezone('America/Los_Angeles'))
This is because timezones are subject to change, and the pytz zone objects contain the entire history and need to be configured for the correct time period. A simple replace doesn't allow for this. Some of those old historic periods will have an odd number of minutes offset.
The standard two line element (TLE) format contains times as 2-digit year plus decimal days, so 16012.375 would be January 12, 2016 at 09:00. Using python's time or datatime modules, how can I convert this to seconds after epoch? I think I should use structured time but I am not sure how. seconds_of is a fictitious function - need to replace with something real.
EDIT: It will be most helpful if the answer is long (verbose) - like one step per line or so, so I can understand what is happening.
EDIT 2: After seeing the comments from #J.F.Sebastian I looked at the link for TLE and found it nowhere states "UTC". So I should point out the initial information and final information are UTC. There is no reference to local time, time zone, or system time.
e.g.
tim = "16012.375"
year = 2000 + int(tim[0:2])
decimal_days = float(tim[2:])
print year, decimal_days
2016, 12.375
# seconds_of is a fictitious function - need to replace with something real
seconds_after_epoch = seconds_of(2016,1,1) + (3600. * 24.) * decimal_days
You could try something like this [EDIT according to the comments].
import datetime
import time
# get year 2 digit and floating seconds days
y_d, nbs = "16012.375".split('.')
# parse to datetime (since midnight and add the seconds) %j Day of the year as a zero-padded decimal number.
d = datetime.datetime.strptime(y_d, "%y%j") + datetime.timedelta(seconds=float("." + nbs) * 24 * 60 * 60)
# 1.0 => 1 day
# from time tuple get epoch time.
time.mktime(d.timetuple())
#1481896800.0
It is easy to get datetime object given year and decimal_days:
>>> from datetime import datetime, timedelta
>>> year = 2016
>>> decimal_days = 12.375
>>> datetime(year, 1, 1) + timedelta(decimal_days - 1)
datetime.datetime(2016, 1, 12, 9, 0)
How to convert the datetime object into "seconds since epoch" depends on the timezone (local, utc, etc). See Converting datetime.date to UTC timestamp in Python e.g., if your input is in UTC then it is simple to get "seconds since the Epoch":
>>> utc_time = datetime(2016, 1, 12, 9, 0)
>>> (utc_time - datetime(1970, 1, 1)).total_seconds()
1452589200.0
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 am trying to write a countdown clock script. I want to use a set date in the future and have it count down in a nice readable format. Hours, Min, Sec. I am going to print to a 16x2 lCD display. The problem I'm having is trying to take the output of the difference between dates into a nice format. I have attached what I have so far. I receive the error:
AttributeError: 'datetime.timedelta' object has no attribute 'strftime'
This is my code:
from datetime import datetime
from time import strftime
deploy = datetime(2015, 3, 21, 0, 0)
mydate = datetime.now() - deploy
print (mydate.strftime("%b %d %H:%M:%S"))
I know how to print to my LCD and create a loop, just need help with this part.
There are two issues:
the time difference may be incorrect if you use local time represented as a naive datetime object if the corresponding local times have different utc offsets e.g., around a DST transition
the difference is timedelta object that has no strftime() method
To fix it, convert deploy from local timezone to UTC:
#!/usr/bin/env python
import time
from datetime import datetime, timedelta
deploy = datetime(2015, 3, 21, 0, 0) # assume local time
timestamp = time.mktime(deploy.timetuple()) # may fail, see the link below
deploy_utc = datetime.utcfromtimestamp(timestamp)
elapsed = deploy_utc - datetime.utcnow() # `deploy` is in the future
where elapsed is the elapsed time not counting leap seconds (such as 2015-07-01 00:59:60 BST+0100).
More details on when time.mktime() may fail see at Find if 24 hrs have passed between datetimes - Python.
To convert timedelta to string, you could use str() function:
print(elapsed) # print full timedelta
# remove microseconds
trunc_micros = timedelta(days=elapsed.days, seconds=elapsed.seconds)
print(trunc_micros) # -> 20 days, 13:44:14 <- 17 chars
# remove comma
print(str(trunc_micros).replace(',', ''))
# -> 20 days 13:44:14 <- 16 chars
If you want a different format then convert to hours, minutes, second using divmod() function:
seconds = elapsed.days*86400 + elapsed.seconds # drop microseconds
minutes, seconds = divmod(seconds, 60)
hours, minutes = divmod(minutes, 60)
print("{hours:02d}:{minutes:02d}:{seconds:02d}".format(**vars()))
# -> 493:44:14
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)