Is it possible to convert seconds into minutes and seconds with this format "mm:ss"?
I try to use datetime.timedelta(seconds=seconds) but it returns hh:mm:ss format.
Thanks in advance!
You can use divmod for this.
hours, remainder = divmod(someSecondsValue, 3600)
minutes, seconds = divmod(remainder, 60)
print(f"{minutes:02}:{seconds:02}")
You can get number of minutes by dividing by 60
and number of seconds by calculating reminder by 60.
total_seconds = 10000
minutes = int(total_seconds / 60)
seconds = total_seconds % 60
print(f"{minutes}:{seconds}")
You could also make a small custom time class and use __format__ to control how you wanna print it out:
class MyTime:
def __init__(self, seconds: int):
self.total_seconds = seconds
def __format__(self, format_spec: str) -> str:
if format_spec == 'm':
minutes = self.total_seconds // 60
seconds = self.total_seconds % 60
return f'{minutes:02}:{seconds:02}'
if format_spec == 'h':
hours = self.total_seconds // 3600
minutes = (self.total_seconds - hours * 3600) // 60
seconds = self.total_seconds % 60
return f'{hours:02}:{minutes:02}:{seconds:02}'
# ...other formats...
return str(self.total_seconds)
x = MyTime(3674)
print(f'Seconds: {x}') # 3674
print(f'Minutes & seconds: {x:m}') # 61:14
print(f'Hours & minutes & seconds: {x:h}') # 01:01:14
def seconds_to_label_converter(seconds):
hours = divmod(seconds,3600)[0]
minutes = divmod(seconds-(hours*3600),60)[0]
remaining_seconds = seconds-((hours*3600)+(minutes*60))
if remaining_seconds == 0 and hours == 0 and minutes == 0:
time_label = "No info"
elif hours > 1:
time_label = f"{hours} Hours {minutes} Minutes {remaining_seconds} Seconds"
elif hours == 1:
time_label = f"{hours} Hour {minutes} Minutes {remaining_seconds} Seconds"
elif hours == 0 and minutes > 1:
time_label = f"{minutes} Minutes {remaining_seconds} Seconds"
elif hours == 0 and minutes == 1:
time_label = f"{minutes} Minute {remaining_seconds} Seconds"
elif hours == 0 and minutes == 0:
time_label = f"{remaining_seconds} Seconds"
print(time_label)
seconds_to_label_converter(21254)
I have a "seconds to label converter" like this. Now I need a function that will do the opposite. But I don't know how to do it.
for example:
label_to_seconds_converter("5 Hours 54 Minutes 14 Seconds")
# >>> OUTPUT = 21254
Try this. Extract specific strings using re and then extract numbers
import re
def seconds_to_label_converter(seconds):
x=re.findall(r'\b\d+\s*hour[s]?\b',seconds.lower())
y=re.findall(r'\b\d+\s*minute[s]?\b',seconds.lower())
z=re.findall(r'\b\d+\s*second[s]?\b',seconds.lower())
secs=0
if x:
for i in re.findall(r'\d+',''.join(x)):
secs +=3600*int(i)
if y:
for i in re.findall(r'\d+',''.join(y)):
secs +=60*int(i)
if z:
for i in re.findall(r'\d+',''.join(z)):
secs +=int(i)
return secs
print(seconds_to_label_converter('4 hours 50 seconds'))
Returns
14450
print(seconds_to_label_converter('4 hours 10 minutes 50 seconds'))
returns
15050
print(seconds_to_label_converter('5 Hours 54 Minutes 14 Seconds'))
Returns
21254
You could do something like this:
def text_to_second(txt: str):
items = [int(x) if x.isnumeric() else x for x in txt.split() ]
seconds = 0
for i in range(0,len(items),2):
a = items[i+1]
if a.lower()=="hours" or a.lower()=="hour":
seconds += 3600*items[i]
elif a.lower()=="minutes" or a.lower()=="minute":
seconds += 60*items[i]
elif a.lower()=="seconds" or a.lower()=="second":
seconds += items[i]
return seconds
print(text_to_second("5 Hours 54 Minutes 14 Seconds"))
#output: 21254
Another option would be to use the zip function:
def label_to_seconds_converter(label: str) -> int:
label_list = label.split()
seconds = 0
for amount, word in zip(label_list[::2], label_list[1::2]):
if "hour" in word.lower():
seconds += int(amount) * 3600
elif "minute" in word.lower():
seconds += int(amount) * 60
else:
seconds += int(amount)
return seconds
print(label_to_seconds_converter("5 Hours 54 Minutes 14 Seconds"))
result
21254
try this :
def label_to_seconds(label):
times = re.findall(r'\b\d+\s*[hours|minutes|seconds]?\b', label.lower())
list_len = len(times)
if list_len == 3:
return int(times[0].strip()) * 3600 + int(times[0].strip()) * 60 + int(times[0].strip())
if list_len == 2:
return int(times[0].strip()) * 60 + int(times[1].strip())
if list_len == 1:
return int(times[0].strip())
else:
print('Invalid Format')
I have 2 fields in the database: confirmed_at and preparation_time
I would like to get two simple functions that should return:
(a) the time residual
and
(b) the % of time remaining.
This is my logic which I am trying to achieve:
when order is confirmed_at I update the database with datetime.now() and preparation_time is indicated in minutes and stored as integer (for example 5 min is stored as 5)
completed_time is confirmed_at + preparation_time
time_remaining is completed_time - now()
order status is completed_time / now() * 100
These are my functions but I cannot make them work:
def get_remaining_time(self):
start_time = datetime(self.confirmed_at)
end_time = (start_time + datetime.timedelta(0,self.preparation_time*60)).time() # days, seconds.
return end_time - datetime.now()
def get_order_status(self):
end_time = (datetime(self.confirmed_at) + datetime.timedelta(0,self.preparation_time*60)).time()
return end_time / datetime.now() * 100
What kind of type returned from functions? If it's timedelta - just turn it into date.
So here it is the solution that I've managed to work out
def get_remaining_time(self):
start_time = self.confirmed_at
end_time = start_time + timedelta(
0, self.preparation_time * 60
) # days, seconds.
return end_time - timezone.now()
def get_time_left(self):
left = self.get_remaining_time()
sec = int(left.total_seconds())
if sec > 60:
return "{} minutes".format(int(sec / 60))
elif sec < 60 and sec > 0:
return "{} seconds".format(sec)
else:
return 0
def get_order_status(self):
left = int(self.get_remaining_time().total_seconds())
if left < 0:
return 100
else:
return round((1 - left / (self.preparation_time * 60)) * 100)
I am having issues with properly implementing the following:
Remove __hours and __minutes.
Adjust the implementation of the mutator and accessor methods. For
example, for __init__(hr, min, sec), validate the values, then set
__seconds = hr * 60 * 60 + min * 60 + sec. This will store the time as seconds. Adjust all the methods to work with __seconds. getSecond()
can use __seconds mod 60 to return only the seconds in the time. Test
all the methods to make sure they still work. (mod is modulus, the
remainder after a division.)
I have used this in my code self.setSecond = (hour * 60 * 60) + (minute * 60 + second)
To properly represent hour, minute and seconds to just seconds I am however having issues with implementing the rest of the program. I'm not sure if I should be printing out just seconds? Also when I change my getSecond() function to return % 60 it is not doing so. I'm assuming because I'm not properly calling it?
Here is my code thus far:
class Clock(object):
def __init__(self, hour, minute, second):
self.setHour(hour)
self.setMinute(minute)
self.setSecond = (hour * 60 * 60) + (minute * 60 + second)
def setHour(self, hour):
self.__hour = hour
if self.__hour > 23:
self.__hour = 0
elif self.__hour < 0:
self.__hour = 0
def getHour(self):
return self.__hour
def setMinute(self, minute):
self.__minute = minute
if self.__minute > 60:
self.__minute = 0
elif self.__minute < 0:
self.__minute = 0
def getMinute(self):
return self.__minute
def setSecond(self, second):
self.__second = second
if self.__second > 60:
self.__second = 0
elif self.__second < 0:
self.__second = 0
def getSecond(self):
return self.__second
def __str__(self):
if self.__hour > 11:
return 'The Time is {}:{}:{} PM'.format(self.__hour, self.__minute, self.__second)
else:
return 'The Time is {}:{}:{} AM'.format(self.__hour, self.__minute, self.setSecond)
stopwatch = Clock(3, 2, 1)
print(stopwatch)
Note: I am aware that this code isn't very pythonic but that is how I was told to keep it (I apologize).
There are 6 changes required primarily:
You don't need to maintain hours and minutes in the class. You maintain only the seconds. So remove the setHour and setMinute methods.
Because you don't maintain the hours and minutes, the getHour and getMinute methods should do the required calculation.
def getHour(self):
return int(self.__second / 3600)
def getMinute(self):
return int(self.__second / 60) % 60
In the init function, call to self.setSecond is not correct. It should be:
def __init__(self, hour, minute, second):
if hour > 23 or hour < 0:
hour = 0
if minute > 60 or minute < 0:
minute = 0
if second > 60 or second < 0:
second = 0
self.setSecond((hour * 60 * 60) + (minute * 60 + second))
And although you mentioned, your getSecond() method does not do a seconds % 60. It should be:
def getSecond(self):
return self.__second % 60
In method def __str__, instead of directly accessing the hours, minutes, seconds, use the accessor methods:
def __str__(self):
if self.getHour() > 11:
return 'The Time is {}:{}:{} PM'.format(self.getHour(), self.getMinute(), self.getSecond())
else:
return 'The Time is {}:{}:{} AM'.format(self.getHour(), self.getMinute(), self.getSecond())
The setSeconds method should not have the check for > 60 because now you will be storing a large number here:
def setSecond(self, second):
self.__second = second
if self.__second < 0:
self.__second = 0
I've been reading posts upon posts of the methods for converting an input number of seconds, which should be output as a formal string with given durations (hours, minutes, seconds). But I want to know how to format it so that it accounts for singularization/pluralization, when I know, for example, 62 seconds should read as "1 minute and 2 seconds" as opposed to 120 seconds which is simply "2 minutes".
One other criteria is that it should return "now" if the seconds is 0.
Here's my code so far:
def format_duration(seconds, granularity = 2):
intervals = (('hours', 3600), ('minutes', 60), ('seconds', 1))
human_time = []
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
human_time.append("{} {}".format(value, name))
else:
return "now"
return ','.join(human_time[:granularity])
Please help! Thanks!
MJ
Your code already works quite nicely, you just have one problem with your return "now" that I fixed in the code below. What else do you want your code to do?
def prettyList(human_time):
if len(human_time) > 1:
return ' '.join([', '.join(human_time[:-1]), "and", human_time[-1]])
elif len(human_time) == 1:
return human_time[0]
else:
return ""
def format_duration(seconds, granularity = 2):
intervals = (('hours', 3600), ('minutes', 60), ('seconds', 1))
human_time = []
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
human_time.append("{} {}".format(value, name))
if not human_time:
return "now"
human_time = human_time[:granularity]
return prettyList(human_time)
Edit: so I added a function to prettify the output, the last terms in the list will be separed by a "and" and all the others before by a comma. This will still work even if you add more intervals in your code (like ('days', 86400)). The output now looks like 2 hours, 1 minute and 43 seconds or 25 minutes and 14 seconds.
Made some tweaks for readability :
def pretty_list(human_time):
return human_time[0] if len(human_time) == 1 else ' '.join([', '.join(human_time[:-1]), "and", human_time[-1]])
def get_intervals(seconds):
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
return (
("hour", h),
("minute", m),
("second", s)
)
def format_duration(seconds, granularity=3):
intervals = get_intervals(seconds)
human_time = []
for name, value in intervals:
if value == 0:
continue
elif value == 1:
human_time.append("{} {}".format(value, name))
else:
human_time.append("{} {}s".format(value, name))
return (pretty_list(human_time[:granularity])) if len(human_time) != 0 else "now"
You can try to code for each variation:
def timestamp(ctime):
sec = int(ctime)
if sec == 0:
return "Now"
m, s = divmod(sec, 60)
h, m = divmod(m, 60)
if h == 1: hr_t = 'Hour'
else: hr_t = 'Hours'
if m == 1: mn_t = 'Minute'
else: mn_t = 'Minutes'
if s == 1: sc_t = 'Second'
else: sc_t = 'Seconds'
time_stamp = ""
if h > 0 and m ==0 and s ==0:
time_stamp = "%02d %s " % (h, hr_t)
elif h > 0:
time_stamp = "%02d %s, " % (h, hr_t)
if m > 0 and s !=0:
time_stamp = time_stamp +"%02d %s and %02d %s" % (m, mn_t, s, sc_t)
elif m > 0 and s == 0:
time_stamp = time_stamp +"%02d %s" % (m, mn_t)
elif m == 0 and s != 0:
time_stamp = time_stamp +"%02d %s" % (s, sc_t)
return time_stamp
print (timestamp(11024))
print (timestamp(0))
print (timestamp(31))
print (timestamp(102))
print (timestamp(61))
print (timestamp(60))
print (timestamp(3600))
print (timestamp(3632))
03 Hours, 03 Minutes and 44 Seconds
Now
31 Seconds
01 Minute and 42 Seconds
01 Minute and 01 Second
01 Minute
01 Hour
01 Hour, 32 Seconds
Or you can use the relativedelta option in dateutil and then pick the bones out of it.
from dateutil.relativedelta import relativedelta
attrs = ['years', 'months', 'days', 'hours', 'minutes', 'seconds']
human_readable = lambda delta: ['%d %s ' % (getattr(delta, attr), getattr(delta, attr) != 1 and attr or attr[:-1]) for attr in attrs if getattr(delta, attr) or attr == attrs[-1]]
readable=''
for i in human_readable(relativedelta(seconds=1113600)):
readable += i
print readable
print human_readable(relativedelta(seconds=13600))
print human_readable(relativedelta(seconds=36))
print human_readable(relativedelta(seconds=60))
print human_readable(relativedelta(seconds=3600))
12 days 21 hours 20 minutes 0 seconds
['3 hours ', '46 minutes ', '40 seconds ']
['36 seconds ']
['1 minute ', '0 seconds ']
['1 hour ', '0 seconds ']
For more examples of the second example see: http://code.activestate.com/recipes/578113-human-readable-format-for-a-given-time-delta/
which is where I stole almost all the second set of code from
I found it! I actually needed more intervals - the durations asked for were lengthier than I thought...
def prettyList(human_time):
if len(human_time) > 1:
return ' '.join([', '.join(human_time[:-1]), "and", human_time[-1]])
elif len(human_time) == 1:
return human_time[0]
else:
return ""
def format_duration(seconds, granularity = 4):
intervals = (('years', 29030400), ('months', 2419200), ('weeks', 604800),('days', 86400),('hours', 3600), ('minutes', 60), ('seconds', 1))
human_time = []
for name, count in intervals:
value = seconds // count
if value:
seconds -= value * count
if value == 1:
name = name.rstrip('s')
human_time.append("{} {}".format(value, name))
if not human_time:
return "now"
human_time = human_time[:granularity]
return prettyList(human_time)
I think that I have covered all of the bases here but I'm sure someone will let me know if I have made an error (large or small) :)
from dateutil.relativedelta import relativedelta
def convertdate(secs):
raw_date = relativedelta(seconds=secs)
years, days = divmod(raw_date.days, 365) # To crudely cater for leap years / 365.2425
hours = raw_date.hours
minutes = raw_date.minutes
seconds = raw_date.seconds
full = [years,days,hours,minutes,seconds]
date_text=['','','','','']
if years == 1: date_text[0] = "Year"
else: date_text[0] = "Years"
if days == 1: date_text[1] = "Day"
else: date_text[1] = "Days"
if hours == 1: date_text[2] = "Hour"
else: date_text[2] = "Hours"
if minutes == 1: date_text[3] = "Minute"
else: date_text[3] = "Minutes"
if seconds == 1: date_text[4] = "Second"
else: date_text[4] = "Seconds"
first_pos = 0
final_pos = 0
element_count = 0
# Find the first and final set positions and the number of returned values
for i in range(5):
if full[i] != 0:
final_pos = i
element_count +=1
if first_pos == 0:
first_pos = i
# Return "now" and any single value
if element_count == 0:
return "Now"
if element_count == 1:
return "%02d %s" % (full[final_pos],date_text[final_pos])
# Initially define the separators
separators=['','','','','']
ret_str=''
for i in range(4):
if full[i] != 0:
separators[i] = ', '
separators[final_pos] = ''
# Redefine the final separator
for i in range(4,-1,-1):
if separators[i] == ', ':
separators[i] = ' and '
break
#Build the readable formatted time string
for i in range(5):
if full[i] != 0:
ret_str += "%02d %s%s" % (full[i],date_text[i],separators[i])
return ret_str
print convertdate(1111113601)
print convertdate(1111113635)
print convertdate(1111113600)
print convertdate(1111111200)
print convertdate(1111104000)
print convertdate(1111104005)
print convertdate(11113240)
print convertdate(11059240)
print convertdate(11113600)
print convertdate(36)
print convertdate(60)
print convertdate(61)
print convertdate(121)
print convertdate(122)
print convertdate(120)
print convertdate(3600)
print convertdate(3601)
35 Years, 85 Days, 02 Hours, 40 Minutes and 01 Second
35 Years, 85 Days, 02 Hours, 40 Minutes and 35 Seconds
35 Years, 85 Days, 02 Hours and 40 Minutes
35 Years, 85 Days and 02 Hours
35 Years and 85 Days
35 Years, 85 Days and 05 Seconds
128 Days, 15 Hours and 40 Seconds
128 Days and 40 Seconds
128 Days, 15 Hours, 06 Minutes and 40 Seconds
36 Seconds
01 Minute
01 Minute and 01 Second
02 Minutes and 01 Second
02 Minutes and 02 Seconds
02 Minutes
01 Hour
01 Hour and 01 Second