Python summing up time - python

In python how do I sum up the following time?
0:00:00
0:00:15
9:30:56

It depends on the form you have these times in, for example if you already have them as datetime.timedeltas, then you could just sum them up:
>>> s = datetime.timedelta(seconds=0) + datetime.timedelta(seconds=15) + datetime.timedelta(hours=9, minutes=30, seconds=56)
>>> str(s)
'9:31:11'

Using timedeltas (tested in Python 3.9):
import datetime
timeList = ['0:00:00', '0:00:15', '9:30:56']
mysum = datetime.timedelta()
for i in timeList:
(h, m, s) = i.split(':')
d = datetime.timedelta(hours=int(h), minutes=int(m), seconds=int(s))
mysum += d
print(str(mysum))
Result:
9:31:11

As a list of strings?
timeList = [ '0:00:00', '0:00:15', '9:30:56' ]
totalSecs = 0
for tm in timeList:
timeParts = [int(s) for s in tm.split(':')]
totalSecs += (timeParts[0] * 60 + timeParts[1]) * 60 + timeParts[2]
totalSecs, sec = divmod(totalSecs, 60)
hr, min = divmod(totalSecs, 60)
print "%d:%02d:%02d" % (hr, min, sec)
Result:
9:31:11

I'm really disappointed if there is not any more pythonic solution... :(
Horrible one ->
timeList = [ '0:00:00', '0:00:15', '9:30:56' ]
ttt = [map(int,i.split()[-1].split(':')) for i in timeList]
seconds=reduce(lambda x,y:x+y[0]*3600+y[1]*60+y[2],ttt,0)
#seconds == 34271
This one looks horrible too ->
zero_time = datetime.datetime.strptime('0:0:0', '%H:%M:%S')
ttt=[datetime.datetime.strptime(i, '%H:%M:%S')-zero_time for i in timeList]
delta=sum(ttt,zero_time)-zero_time
# delta==datetime.timedelta(0, 34271)
# str(delta)=='9:31:11' # this seems good, but
# if we have more than 1 day we get for example str(delta)=='1 day, 1:05:22'
Really frustrating is also this ->
sum(ttt,zero_time).strftime('%H:%M:%S') # it is only "modulo" 24 :(
I really like to see one-liner so, I tried to make one in python3 :P (good result but horrible look)
import functools
timeList = ['0:00:00','0:00:15','9:30:56','21:00:00'] # notice additional 21 hours!
sum_fnc=lambda ttt:(lambda a:'%02d:%02d:%02d' % (divmod(divmod(a,60)[0],60)+(divmod(a,60)[1],)))((lambda a:functools.reduce(lambda x,y:x+y[0]*3600+y[1]*60+y[2],a,0))((lambda a:[list(map(int,i.split()[-1].split(':'))) for i in a])(ttt)))
# sum_fnc(timeList) -> '30:40:11'

lines = ["0:00:00", "0:00:15", "9:30:56"]
total = 0
for line in lines:
h, m, s = map(int, line.split(":"))
total += 3600*h + 60*m + s
print "%02d:%02d:%02d" % (total / 3600, total / 60 % 60, total % 60)

Assuming you want to add up the seconds for a total time:
def parse_time(s):
hour, min, sec = s.split(':')
try:
hour = int(hour)
min = int(min)
sec = int(sec)
except ValueError:
# handle errors here, but this isn't a bad default to ignore errors
return 0
return hour * 60 * 60 + min * 60 + sec
print parse_time('0:00:00') + parse_time('0:00:15') + parse_time('9:30:56')

from datetime import timedelta
h = ['3:00:00','1:07:00', '4:00:00', '4:05:00', '4:10:00', '4:03:00']
def to_td(h):
ho, mi, se = h.split(':')
return timedelta(hours=int(ho), minutes=int(mi), seconds=int(se))
print(str(sum(map(to_td, h), timedelta())))
# Out[31]: 20:25:00

Naive approach (without exception handling):
#!/usr/bin/env python
def sumup(*times):
cumulative = 0
for t in times:
hours, minutes, seconds = t.split(":")
cumulative += 3600 * int(hours) + 60 * int(minutes) + int(seconds)
return cumulative
def hms(seconds):
"""Turn seconds into hh:mm:ss"""
hours = seconds / 3600
seconds -= 3600*hours
minutes = seconds / 60
seconds -= 60*minutes
return "%02d:%02d:%02d" % (hours, minutes, seconds)
if __name__ == '__main__':
print hms(sumup(*("0:00:00", "0:00:15", "9:30:56")))
# will print: 09:31:11

Bellow is a solution using list comprehension:
from datetime import timedelta
def time_sum(time: List[str]) -> timedelta:
"""
Calculates time from list of time hh:mm:ss format
"""
return sum(
[
timedelta(hours=int(ms[0]), minutes=int(ms[1]), seconds=int(ms[2]))
for t in time
for ms in [t.split(":")]
],
timedelta(),
)
Example:
time_list = ["0:00:00", "0:00:15", "9:30:56"]
total = time_sum(time_list)
print(f"Total time: {total}")

Related

Python Timer Cooldown Example

I'm looking for a cooldown timer for python, basically just to print days,hours,minutes,seconds left from a certain date.
Thanks very much!
You can get the counter with the help of time delta function.
import datetime
import time
future_date = datetime.datetime.now()+ datetime.timedelta(seconds=3)
while True:
curr_date = datetime.datetime.now()
rem_time = future_date - curr_date
total_seconds = int(rem_time.total_seconds())
if total_seconds > 0:
days, h_remainder = divmod(total_seconds, 86400)
hours, remainder = divmod(h_remainder, 3600)
minutes, seconds = divmod(remainder, 60)
print("Time Left: {} days, {} hours, {} minutes, {} seconds".format(days, hours, minutes, seconds))
time.sleep(1)
else:
break
sample output will be:
Time Left: 0 days, 0 hours, 0 minutes, 2 seconds
Time Left: 0 days, 0 hours, 0 minutes, 1 seconds
Try this. The module datetime is preinstalled on Python, I believe.
import datetime
while True:
print("\033[H\033[J")
present = datetime.datetime.now()
future = datetime.datetime(2022, 3, 31, 8, 0, 0)
difference = future - present
print(difference)
The format for datetime's future is: year, month, day, hour, minute, second.
Or, if you'd like to have user input:
import datetime
year = int(input('Enter the year of the end date: '))
month = int(input('Enter the month of the end date: '))
day = int(input('Enter the day of the end date: '))
hour = int(input('Enter the hour of the end date: '))
minute = int(input('Enter the minute of the end date: '))
second = int(input('Enter the second of the end date (a little tricky): '))
future = datetime.datetime(year, month, day, hour, minute, second)
while True:
print("\033[H\033[J")
present = datetime.datetime.now()
difference = future - present
if present >= future:
break
print(difference)
print('Time reached!')
You can use the seconds from a timedelta from subtracting two dates to calculate the days, hours, minutes and seconds like this:
from datetime import datetime
import time
totalSecs = 1 #So the while loop doesn't stop immidiately
while totalSecs > 0:
startDate = datetime.now() #Can be any date
endDate = datetime(2021, 12, 25)
delta = endDate - startDate
totalSecs = delta.total_seconds()
days = divmod(totalSecs, 86400)
hrs = divmod(days[1], 3600)
mins = divmod(hrs[1], 60)
seconds = divmod(mins[1], 1)
print("{:02d}:{:02d}:{:02d}:{:02d}".format(int(days[0]), int(hrs[0]), int(mins[0]), int(seconds[0]))) #Zero pad all the numbers
time.sleep(1) #Print every second.
Thank you all for your replies, i've done a mistake when i made the post. Is not from a date. Is a countdown in day,hours,minutes,seconds from a certain amount of seconds. Let's say i've got 31104000 seconds and i want to print how many days,hours,minutes,seconds left from that amount of seconds.
The code i've got now is a bit trivial and i can't print seconds in realtime.
def SecondToDHM(time):
if time < 60:
return "%.2f %s" % (time, SECOND)
second = int(time % 60)
minute = int((time / 60) % 60)
hour = int((time / 60) / 60) % 24
day = int(int((time / 60) / 60) / 24)
text = ""
if day > 0:
text += str(day) + DAY
text += " "
if hour > 0:
text += str(hour) + HOUR
text += " "
if minute > 0:
text += str(minute) + MINUTE
text += " "
if second > 0:
text += str(second) + SECOND
return text
import datetime
a = datetime.datetime.now()
"%s:%s.%s" % (a.minute, a.second, str(a.microsecond))

How to convert elapsed time string to seconds in Python

Does anyone know if there is an "easy" function which will convert the following elapsed time string to seconds?
2d1h39m53s
Depending on how much time has elapsed, not all the fields will be present.
I've looked at strptime and datetime but nothing seemed to fit the bill without writing my own function for this. Just looking to save some time.
Thx
I wrote it to days before to clearly verify the runtime. After the two defs below just write 'tic()' at the start point in your code where you want count and 'toc()' at the end point, and it will give you a clear time data to read. Hope it helps.
import time
import math
def tic():
global startTime_for_tictoc
startTime_for_tictoc = time.time()
def toc():
if 'startTime_for_tictoc' in globals():
tf = time.time() - startTime_for_tictoc;
if tf < 60:
print("\nElapsed time: %f seconds.\n" % tf)
elif 60 < tf < 3600:
mm = math.floor(tf/60)
ss = tf - (60*mm)
print("\nElapsed time: %d minute(s) and %f seconds.\n" % (mm, ss))
elif 3600 < tf < 86400:
hh = math.floor(tf/3600)
mm = math.floor((tf-(hh*3600))/60)
ss = tf - (hh*3600) - (60*mm)
print("\nElapsed time: %d hour(s) %d minute(s) and %f seconds.\n" % (hh, mm, ss))
elif tf > 86400:
dd = math.floor(tf/86400)
hh = math.floor((tf-(dd*86400))/3600)
mm = math.floor((tf-(dd*86400)-(hh*3600))/60)
ss = tf - (86400*dd) - (hh*3600) - (60*mm)
print("\nElapsed time: %d day(s) %d hour(s) %d minute(s) and %f seconds.\n" % (dd, hh, mm, ss))
else:
print("\nToc: start time not set")
Not sure if there is a function out there but this will get the job done. Will work with values such as "2d1h53s" as well.
d = []
h = []
m = []
s = []
sd = 0
sh = 0
sm = 0
ss = 0
str = "2d1h39m53s"
i = 0
if str.find("d") > 0:
i = str.find("d")
d.append(str[0:i])
str = str[i:]
if str.find("h") > 0:
i = str.find("h")
h.append(str[1:i])
str = str[i:]
if str.find("m") > 0:
i = str.find("m")
m.append(str[1:i])
str = str[i:]
if str.find("s") > 0:
i = str.find("s")
s.append(str[1:i])
str = str[i:]
try:
sd = float(d[0]) * 24 * 60 * 60
except:
sd = 0
try:
sh = float(h[0]) * 60 * 60
except:
sh = 0
try:
sm = float(m[0]) * 60
except:
sm = 0
try:
ss = float(s[0])
except:
ss = 0
print("seconds")
sec = sd + sh + sm + ss
print(sec)
If your datetime has exactly the given format you could do the following:
import re
import numpy as np
from functools import reduce
split_strings = ['D', 'h','m','s']
def datestring_to_seconds(datestring):
values_and_units = [(int(string[:-1]), string[-1]) for string in [re.search(f"([0-9]+){split_string}",
f"{datestring}".replace('d', 'D')).group(0) for split_string in split_strings]]
return reduce(lambda x,y : x+y, [np.timedelta64(*x) for x in values_and_units])/np.timedelta64(1, 's')
result
datestring_to_seconds("2d1h39m53s")
178793.0
Some explanation:
First search in the string for any to a match of up to two digits in front of one of the split_strings (e.g. 39m) then we convert this to a tuple (39, "m"). We perform this operation with every string in split_strings and save the result in the list values_and_units, which looks in our special case like this:
[(2, 'D'), (1, 'h'), (39, 'm'), (53, 's')]
Each element of these can now be casted to a numpy timedelta64. The reduce operation adds up all the timedeltas and dividing by a np.timedelta64(1, 's') gives us a float with the desired seconds.
Here is a pure python solution.
import re
s = '2d1h39m53s'
d = {'d':86400,'h':3600, 'm':60, 's':1}
secs = 0
m = re.match(r'(\d+)([dhms])', s)
while m is not None:
secs += int(m.group(1)) * d[m.group(2)]
s = re.sub(r'\d+[dhms]', '', s, 1)
m = re.match(r'(\d+)([dhms])', s)
print(secs)
print(secs)
Prints: 178793
EDIT: To use match.end() to locate beginning of next search. Not destructive of string, s, and a cleaner solution.
import re
s = '2d1h39m53s'
d = {'d':86400,'h':3600, 'm':60, 's':1}
secs = 0
pat = re.compile('(\d+)([dhms])')
m = pat.search(s)
while m is not None:
pos = m.end()
secs += int(m.group(1)) * d[m.group(2)]
m = pat.search(s, pos)
print(secs)

Python timestamp to time since conversion

I have a database column the holds timestamps in UNIX format, I am looking for a way to compare those timestamps to a timestamp from the time right now and print how many seconds/hours/days since the original timestamp.
Just to confirm I am NOT looking for a conversion from 1489757456 to 03/17/2017 # 1:30pm. I AM looking for a conversion from 1489757456 to 1m ago/2hr ago/3d ago ect.
datetime.datetime.fromtimestamp()
to convert your unix timestamp to a datetitme
datetime.datetime.now()
to get the current datetime
dateutil.relativedelta.relativedelta(dt1, dt2, ...)
to get the difference with respect to leap years.
References:
https://docs.python.org/3.6/library/datetime.html
http://dateutil.readthedocs.io/en/stable/relativedelta.html
Function, like this will generate output for hours, mins and seconds from seconds number.
def secondsToHms(d):
d = int(d);
h = math.floor(d / 3600)
m = math.floor(d % 3600 / 60)
s = math.floor(d % 3600 % 60)
htext = " hour, " if h == 1 else " hours, "
hDisplay = str(h) + htext if h > 0 else ""
mtext = " minute, " if m == 1 else " minutes, "
mDisplay = str(m) + mtext if m > 0 else ""
stext = " second" if s == 1 else " seconds"
sDisplay = str(s) + stext if s > 0 else ""
return hDisplay + mDisplay + sDisplay;
For example:
secondsToHms(344334)
>> 95.0 hours, 38.0 minutes, 54.0 seconds
So you can add your preferred formatting and also add days/months if needed in similar fashion.

Python Time Math

I want to write a program that allows the user to enter in a start time hour, end time hour, and number of divisions.
So they might enter 9, 10, and 4 which should mean a start time of 9:00AM, end of 10:00AM and to split the range 4 times, resulting in an output of 9:00, 9:15, 9:30, 9:45.
I've tried using the time module and datetime, but cannot get the addition of time to work. I do not care about date.
I can calculate the time split, but the actual addition to the start time is evading me.
I have a hodge-podge of code, and the following is mostly me experimenting trying to figure out how to make this work. I've tried adding the minutes, tried converting to seconds, delved into datetime, tried the time module, but can't seem to get it to work. There are plenty of examples of how to "add 15 minutes to now" but the issue is I don't want to start at the "now", but rather let the user decide start time.
Thank you.
time_start = "9"
time_end = "10"
time_split = "4"
if len(time_start) == 1:
time_start = "0" + str(time_start) + ":00"
else:
time_start = str(time_start) + ":00"
if len(time_end) == 1:
time_end = "0" + str(time_end) + ":00"
else:
time_end = str(time_end) + ":00"
print time_start
print time_end
s1 = time_start + ':00'
s2 = time_end + ':00'
FMT = '%H:%M:%S'
tdelta = datetime.strptime(s2, FMT) - datetime.strptime(s1, FMT)
divided = tdelta / int(time_split)
print tdelta
print divided
s3 = str(divided)
print "s1 time start: " + str(s1)
print "s2 time end: " + str(s2)
print "s3 time divided: " + str(s3)
ftr = [3600,60,1]
add_seconds = sum([a*b for a,b in zip(ftr, map(int,s3.split(':')))])
print "s3 time divided seconds: " + str(add_seconds)
print "time delta: " + str(tdelta)
EDIT: I did a small bit of research and found a much better solution that elegantly handles resolution to the millisecond. Please implement this code instead (though I will save the old code for posterity)
import datetime
start_time = 9 # per user input
end_time = 10 # per user input
divisions = 7 # per user input
total_time = end_time - start_time
start_time = datetime.datetime.combine(datetime.date.today(),datetime.time(start_time))
end_time = start_time + datetime.timedelta(hours=total_time)
increment = total_time*3600000//divisions # resolution in ms
times = [(start_time+datetime.timedelta(milliseconds=increment*i)).time()
for i in range(divisions)]
from pprint import pprint
pprint(list(map(str,times)))
# ['09:00:00',
# '09:08:34.285000',
# '09:17:08.570000',
# '09:25:42.855000',
# '09:34:17.140000',
# '09:42:51.425000',
# '09:51:25.710000']
If I were you, I'd do my math as raw minutes and use datetime.time only to save the results as something more portable.
Try this:
import datetime
start_time = 9 # per user input
end_time = 10 # per user input
divisions = 4 # per user input
total_minutes = (end_time-start_time)*60
increment = total_minutes // divisions
minutes = [start_time*60]
while minutes[-1] < end_time*60:
# < end_time*60 - increment to exclude end_time from result
minutes.append(minutes[-1] + increment)
times = [datetime.time(c//60,c%60) for c in minutes]
# [09:00:00,
# 09:15:00,
# 09:30:00,
# 09:45:00,
# 10:00:00]

Converting fractional days to H:M:S.MS - Two examples

Of the two methods of calculating a fractional day to local time, which one would you consider the best way and why?
Edit: 'Fractional day' means here the decimal part of a Julian day jd: jd - (math.floor(jd - 0.5) + 0.5) (this is because 0:00:00 is at jd.5)
#classmethod
def fromfractional(cls, frac, **kwargs):
changed = False
f = lambda x: decimal.dec(floor(x))
if not isinstance(frac, decimal.Decimal):
frac = decimal.dec(frac)
hours = decimal.dec(D24 * (frac - f(frac)))
if hours < 1:
hours += 1 # Or else microseconds won't be calculated correctly
changed = True
minutes = decimal.dec(D60 * (hours - f(hours)))
seconds = decimal.dec(D60 * (minutes - f(minutes)))
ms = decimal.dec(DKS * (seconds - f(seconds)))
if changed:
hours -= 1
return int(hours), int(minutes), int(seconds), int(ms)
#classmethod
def fromfractional2(cls, x):
d = lambda x: decimal.Decimal(str(x))
total = d(x) * d(86400000000000)
hours = (total - (total % d(3600000000000))) / d(3600000000000)
total = total % d(3600000000000)
minutes = (total - (total % d(60000000000))) / d(60000000000)
total = total % d(60000000000)
seconds = (total - (total % d(1000000000))) / d(1000000000)
total = total % d(1000000000)
ms = (total - (total % d(1000000))) / d(1000000)
total = total % d(1000000)
mics = (total - (total % d(1000))) / d(1000)
return int(hours), int(minutes), int(seconds), int(ms)
D24 = decimal.Decimal('24')
DMS = decimal.Decimal('86400000.0')
D60 = decimal.Decimal('60')
D3600 = decimal.Decimal('3600')
D1440=decimal.Decimal('1400')
DKS=decimal.Decimal('1000')
DTS=decimal.Decimal('86400')
I think you are trying to get from something like:
1.2256 days
To:
1 day, 5 hours, 24 minutes, 51 seconds
but with microseconds, too?
Here's how I generated the above response:
def nice_repr(timedelta, display="long"):
"""
Turns a datetime.timedelta object into a nice string repr.
display can be "minimal", "short" or "long" [default].
>>> from datetime import timedelta as td
>>> nice_repr(td(days=1, hours=2, minutes=3, seconds=4))
'1 day, 2 hours, 3 minutes, 4 seconds'
>>> nice_repr(td(days=1, seconds=1), "minimal")
'1d, 1s'
"""
assert isinstance(timedelta, datetime.timedelta), "First argument must be a timedelta."
result = ""
weeks = timedelta.days / 7
days = timedelta.days % 7
hours = timedelta.seconds / 3600
minutes = (timedelta.seconds % 3600) / 60
seconds = timedelta.seconds % 60
if display == 'minimal':
words = ["w", "d", "h", "m", "s"]
elif display == 'short':
words = [" wks", " days", " hrs", " min", " sec"]
else:
words = [" weeks", " days", " hours", " minutes", " seconds"]
values = [weeks, days, hours, minutes, seconds]
for i in range(len(values)):
if values[i]:
if values[i] == 1 and len(words[i]) > 1:
result += "%i%s, " % (values[i], words[i].rstrip('s'))
else:
result += "%i%s, " % (values[i], words[i])
return result[:-2]

Categories

Resources