Python print() function not recalculating variables in a while loop - python

I am attempting to write a program that will calculate the difference in a given time and the actual time then display that delta in a while loop. I have been able to get most of this working, the only issue I have found so far is the time variables in the print statement do not update as the loop runs.
import datetime
import time
from os import system
from sys import platform
clear_screen = lambda: system("cls" if platform == "win32" else "clear")
# print("What is the time and date of your event?")
# year = int(input("Year: "))
# month = int(input("Month: "))
# day = int(input("Day: "))
# hour = int(input("Hour: "))
# minute = int(input("Minute: "))
i = 0
year = 2023
month = 1
day = 27
hour = 12
minute = 0
second = 00
today = datetime.datetime.now()
date_entry = datetime.datetime(year, month, day, hour, minute, second)
print(f"The current date & time: {today}")
print(f"The big day is: {date_entry}")
print()
print()
print(f"Tiff's Big day is going to be here soon:")
print()
event_count = date_entry - today
event_hour = event_count.total_seconds() / 3600
event_min = ((event_hour % 1) * (60 / 100)) * 100
event_sec = ((event_min % 1) * (60 / 100)) * 100
def countdown():
print(f"{event_hour:.0f} Hours, {event_min:.0f} Minutes, {event_sec:.0f} seconds until big mode!!!!!")
while i < 50:
i += 1
countdown()
time.sleep(2)
# clear_screen()`
I have a feeling that the time variables in the print statement are not recalculating... I have tried restructuring the program by moving the variables into the countdown() function. That had the same result.
I am expecting the script to output hours, minutes and seconds until a defined time. This part works great. Then pause for 2 seconds (this works) then print the statement again after it recalculates the time delta. This is were it fails, prints the exact same time as in the first print statement.
You might also notice the clear_screen(). This kinda works, it will clear all of the output. I am looking to make it clear the last line printed in the loop (ie: 40 Hours, 12 Minutes, 56 seconds until big mode!!!!!) This is something I haven't looked at much yet. If you have any suggestions...
Thanks in advance for any suggestions.
Output:
The current date & time: 2023-01-25 19:48:04.383425
The big day is: 2023-01-27 12:00:00
Tiff's Big day is going to be here soon:
40 Hours, 12 Minutes, 56 seconds until big mode!!!!!
40 Hours, 12 Minutes, 56 seconds until big mode!!!!!
40 Hours, 12 Minutes, 56 seconds until big mode!!!!!
40 Hours, 12 Minutes, 56 seconds until big mode!!!!!
40 Hours, 12 Minutes, 56 seconds until big mode!!!!!

Be careful with calling time functions, the time is assigned to a variable only the first time, here is an example in the REPL:
>>> import time
>>> time.time()
1674700748.035392
>>> time.time()
1674700749.2911549
>>> time.time()
1674700750.440412
>>> time.time()
1674700751.571879
>>> x = time.time()
>>> x
1674700755.0605464
>>> x
1674700755.0605464
>>> x
1674700755.0605464
>>> x
1674700755.0605464
>>> for i in range(5): print(time.time())
...
1674700912.1213877
1674700912.1214447
1674700912.1214585
1674700912.1214688
1674700912.1214786
>>> for i in range(5): print(x)
...
1674700755.0605464
1674700755.0605464
1674700755.0605464
1674700755.0605464
1674700755.0605464
As you can see if I call time.time multiple times the time changes, but if I assign it to x, then x always has the same value.

Below is the code I wrote to solve my problem:
import datetime
import time
from os import system
from sys import platform
import cursor
# print("What is the time and date of your event?")
# year = int(input("Year: "))
# month = int(input("Month: "))
# day = int(input("Day: "))
# hour = int(input("Hour: "))
# minute = int(input("Minute: "))
year = 2023
month = 1
day = 27
hour = 12
minute = 0
second = 00
date_entry = datetime.datetime(year, month, day, hour, minute, second)
print(f"The current date & time: {datetime.datetime.now()}")
print(f"The big day is: {date_entry}")
print()
print()
print(f"Tiff's Big day is going to be here soon:")
print()
while True:
event_count = date_entry - datetime.datetime.now()
event_hour = event_count.total_seconds() / 3600
event_min = ((event_hour % 1) * (60 / 100)) * 100
event_sec = ((event_min % 1) * (60 / 100)) * 100
print(f"{event_hour:.0f} Hours, {event_min:.0f} Minutes, {event_sec:.0f} seconds until big time!!!", end = "\r")
cursor.hide()
time.sleep(.5)

Related

Add hours to workday in python

I need the following script to compute the working hours from 9 am to 6 pm, so that if I add 5 hours it will be added from 9 am the next day.
Example: if it is now 5 pm and I add 5 hours and the working day ends at 6 pm, the output would be: 13 hours.
17 + 1 = 18 and
9 + 4 = 13 hs
So far the script computes hours regardless of the labor restriction.
from datetime import datetime, timedelta
updated = ( datetime.now() +
timedelta( hours = 5 )).strftime('%H:%M:%S')
print( updated )
--22:12:00
Here you are:
workday_begin = time(9)
workday_end = time(18)
# compute workday length
workday_hours = datetime.combine(date.today(), workday_end) - datetime.combine(date.today(), workday_begin)
# this is timedelta from your example
duration_hours = timedelta(hours=17)
# ignore times longer than a workday
day_cnt = 0 # this could be used to know how many day we've skipped, not part of question tho
while duration_hours > workday_hours:
day_cnt += 1
duration_hours -= workday_hours
now = datetime.now()
# now = datetime(2021,12,10,11,25,16)
if workday_begin < now.time() < workday_end:
# now is in work-hours
if datetime.combine(date.today(), workday_end) - now < duration_hours:
# duration would exceed work-hours, jumping to next day
day_cnt += 1
duration_hours -= (datetime.combine(date.today(), workday_end) - now)
updated = datetime.combine(date.today(), workday_begin) + duration_hours
else:
# everything is fine, just add hours
updated = now + duration_hours
else:
# now is not in work-hours. Add remaining duration to workday begin
updated = datetime.combine(date.today(), workday_begin) + duration_hours
# keep just a time part
updated = updated.time().strftime('%H:%M:%S')
print( updated )
I hope I understood your question.

Converting seconds to minutes and hours and writing to a CSV file [duplicate]

I have a function that returns information in seconds, but I need to store that information in hours:minutes:seconds.
Is there an easy way to convert the seconds to this format in Python?
You can use datetime.timedelta function:
>>> import datetime
>>> str(datetime.timedelta(seconds=666))
'0:11:06'
By using the divmod() function, which does only a single division to produce both the quotient and the remainder, you can have the result very quickly with only two mathematical operations:
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
And then use string formatting to convert the result into your desired output:
print('{:d}:{:02d}:{:02d}'.format(h, m, s)) # Python 3
print(f'{h:d}:{m:02d}:{s:02d}') # Python 3.6+
I can hardly name that an easy way (at least I can't remember the syntax), but it is possible to use time.strftime, which gives more control over formatting:
from time import strftime
from time import gmtime
strftime("%H:%M:%S", gmtime(666))
'00:11:06'
strftime("%H:%M:%S", gmtime(60*60*24))
'00:00:00'
gmtime is used to convert seconds to special tuple format that strftime() requires.
Note: Truncates after 23:59:59
Using datetime:
With the ':0>8' format:
from datetime import timedelta
"{:0>8}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{:0>8}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{:0>8}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Without the ':0>8' format:
"{}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Using time:
from time import gmtime
from time import strftime
# NOTE: The following resets if it goes over 23:59:59!
strftime("%H:%M:%S", gmtime(125))
# Result: '00:02:05'
strftime("%H:%M:%S", gmtime(60*60*24-1))
# Result: '23:59:59'
strftime("%H:%M:%S", gmtime(60*60*24))
# Result: '00:00:00'
strftime("%H:%M:%S", gmtime(666777))
# Result: '17:12:57'
# Wrong
This is my quick trick:
from humanfriendly import format_timespan
secondsPassed = 1302
format_timespan(secondsPassed)
# '21 minutes and 42 seconds'
For more info Visit:
https://humanfriendly.readthedocs.io/en/latest/api.html#humanfriendly.format_timespan
The following set worked for me.
def sec_to_hours(seconds):
a=str(seconds//3600)
b=str((seconds%3600)//60)
c=str((seconds%3600)%60)
d=["{} hours {} mins {} seconds".format(a, b, c)]
return d
print(sec_to_hours(10000))
# ['2 hours 46 mins 40 seconds']
print(sec_to_hours(60*60*24+105))
# ['24 hours 1 mins 45 seconds']
A bit off topic answer but maybe useful to someone
def time_format(seconds: int) -> str:
if seconds is not None:
seconds = int(seconds)
d = seconds // (3600 * 24)
h = seconds // 3600 % 24
m = seconds % 3600 // 60
s = seconds % 3600 % 60
if d > 0:
return '{:02d}D {:02d}H {:02d}m {:02d}s'.format(d, h, m, s)
elif h > 0:
return '{:02d}H {:02d}m {:02d}s'.format(h, m, s)
elif m > 0:
return '{:02d}m {:02d}s'.format(m, s)
elif s > 0:
return '{:02d}s'.format(s)
return '-'
Results in:
print(time_format(25*60*60 + 125))
>>> 01D 01H 02m 05s
print(time_format(17*60*60 + 35))
>>> 17H 00m 35s
print(time_format(3500))
>>> 58m 20s
print(time_format(21))
>>> 21s
This is how I got it.
def sec2time(sec, n_msec=3):
''' Convert seconds to 'D days, HH:MM:SS.FFF' '''
if hasattr(sec,'__len__'):
return [sec2time(s) for s in sec]
m, s = divmod(sec, 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)
if n_msec > 0:
pattern = '%%02d:%%02d:%%0%d.%df' % (n_msec+3, n_msec)
else:
pattern = r'%02d:%02d:%02d'
if d == 0:
return pattern % (h, m, s)
return ('%d days, ' + pattern) % (d, h, m, s)
Some examples:
$ sec2time(10, 3)
Out: '00:00:10.000'
$ sec2time(1234567.8910, 0)
Out: '14 days, 06:56:07'
$ sec2time(1234567.8910, 4)
Out: '14 days, 06:56:07.8910'
$ sec2time([12, 345678.9], 3)
Out: ['00:00:12.000', '4 days, 00:01:18.900']
hours (h) calculated by floor division (by //) of seconds by 3600 (60 min/hr * 60 sec/min)
minutes (m) calculated by floor division of remaining seconds (remainder from hour calculation, by %) by 60 (60 sec/min)
similarly, seconds (s) by remainder of hour and minutes calculation.
Rest is just string formatting!
def hms(seconds):
h = seconds // 3600
m = seconds % 3600 // 60
s = seconds % 3600 % 60
return '{:02d}:{:02d}:{:02d}'.format(h, m, s)
print(hms(7500)) # Should print 02h05m00s
If you need to get datetime.time value, you can use this trick:
my_time = (datetime(1970,1,1) + timedelta(seconds=my_seconds)).time()
You cannot add timedelta to time, but can add it to datetime.
UPD: Yet another variation of the same technique:
my_time = (datetime.fromordinal(1) + timedelta(seconds=my_seconds)).time()
Instead of 1 you can use any number greater than 0. Here we use the fact that datetime.fromordinal will always return datetime object with time component being zero.
dateutil.relativedelta is convenient if you need to access hours, minutes and seconds as floats as well. datetime.timedelta does not provide a similar interface.
from dateutil.relativedelta import relativedelta
rt = relativedelta(seconds=5440)
print(rt.seconds)
print('{:02d}:{:02d}:{:02d}'.format(
int(rt.hours), int(rt.minutes), int(rt.seconds)))
Prints
40.0
01:30:40
Here is a way that I always use: (no matter how inefficient it is)
seconds = 19346
def zeroes (num):
if num < 10: num = "0" + num
return num
def return_hms(second, apply_zeroes):
sec = second % 60
min_ = second // 60 % 60
hrs = second // 3600
if apply_zeroes > 0:
sec = zeroes(sec)
min_ = zeroes(min_)
if apply_zeroes > 1:
hrs = zeroes(hrs)
return "{}:{}:{}".format(hrs, min_, sec)
print(return_hms(seconds, 1))
RESULT:
5:22:26
Syntax of return_hms() function
The return_hms() function is used like this:
The first variable (second) is the amount of seconds you want to convert into h:m:s.
The second variable (apply_zeroes) is formatting:
0 or less: Apply no zeroes whatsoever
1: Apply zeroes to minutes and seconds when they're below 10.
2 or more: Apply zeroes to any value (including hours) when they're below 10.
Here is a simple program that reads the current time and converts it to a time of day in hours, minutes, and seconds
import time as tm #import package time
timenow = tm.ctime() #fetch local time in string format
timeinhrs = timenow[11:19]
t=tm.time()#time.time() gives out time in seconds since epoch.
print("Time in HH:MM:SS format is: ",timeinhrs,"\nTime since epoch is : ",t/(3600*24),"days")
The output is
Time in HH:MM:SS format is: 13:32:45
Time since epoch is : 18793.335252338384 days
You can divide seconds by 60 to get the minutes
import time
seconds = time.time()
minutes = seconds / 60
print(minutes)
When you divide it by 60 again, you will get the hours
In my case I wanted to achieve format
"HH:MM:SS.fff".
I solved it like this:
timestamp = 28.97000002861023
str(datetime.fromtimestamp(timestamp)+timedelta(hours=-1)).split(' ')[1][:12]
'00:00:28.970'
The solutions above will work if you're looking to convert a single value for "seconds since midnight" on a date to a datetime object or a string with HH:MM:SS, but I landed on this page because I wanted to do this on a whole dataframe column in pandas. If anyone else is wondering how to do this for more than a single value at a time, what ended up working for me was:
mydate='2015-03-01'
df['datetime'] = datetime.datetime(mydate) + \
pandas.to_timedelta(df['seconds_since_midnight'], 's')
I looked every answers here and still tried my own
def a(t):
print(f"{int(t/3600)}H {int((t/60)%60) if t/3600>0 else int(t/60)}M {int(t%60)}S")
Results:
>>> a(7500)
2H 5M 0S
>>> a(3666)
1H 1M 6S
Python: 3.8.8
division = 3623 // 3600 #to hours
division2 = 600 // 60 #to minutes
print (division) #write hours
print (division2) #write minutes
PS My code is unprofessional

timedelta64 presented with 0 days when smaller then 1 day [duplicate]

I get a start_date like this:
from django.utils.timezone import utc
import datetime
start_date = datetime.datetime.utcnow().replace(tzinfo=utc)
end_date = datetime.datetime.utcnow().replace(tzinfo=utc)
duration = end_date - start_date
I get output like this:
datetime.timedelta(0, 5, 41038)
How do I convert this into normal time like the following?
10 minutes, 1 hour like this
There's no built-in formatter for timedelta objects, but it's pretty easy to do it yourself:
days, seconds = duration.days, duration.seconds
hours = days * 24 + seconds // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
Or, equivalently, if you're in Python 2.7+ or 3.2+:
seconds = duration.total_seconds()
hours = seconds // 3600
minutes = (seconds % 3600) // 60
seconds = seconds % 60
Now you can print it however you want:
'{} minutes, {} hours'.format(minutes, hours)
For example:
def convert_timedelta(duration):
days, seconds = duration.days, duration.seconds
hours = days * 24 + seconds // 3600
minutes = (seconds % 3600) // 60
seconds = (seconds % 60)
return hours, minutes, seconds
td = datetime.timedelta(2, 7743, 12345)
hours, minutes, seconds = convert_timedelta(td)
print '{} minutes, {} hours'.format(minutes, hours)
This will print:
9 minutes, 50 hours
If you want to get "10 minutes, 1 hour" instead of "10 minutes, 1 hours", you need to do that manually too:
print '{} minute{}, {} hour{}'.format(minutes, 's' if minutes != 1 else '',
hours, 's' if minutes != 1 else '')
Or you may want to write an english_plural function to do the 's' bits for you, instead of repeating yourself.
From your comments, it sounds like you actually want to keep the days separate. That's even easier:
def convert_timedelta(duration):
days, seconds = duration.days, duration.seconds
hours = seconds // 3600
minutes = (seconds % 3600) // 60
seconds = (seconds % 60)
return days, hours, minutes, seconds
If you want to convert this to a single value to store in a database, then convert that single value back to format it, do this:
def dhms_to_seconds(days, hours, minutes, seconds):
return (((days * 24) + hours) * 60 + minutes) * 60 + seconds
def seconds_to_dhms(seconds):
days = seconds // (3600 * 24)
hours = (seconds // 3600) % 24
minutes = (seconds // 60) % 60
seconds = seconds % 60
return days, hours, minutes, seconds
So, putting it together:
def store_timedelta_in_database(thingy, duration):
seconds = dhms_to_seconds(*convert_timedelta(duration))
db.execute('INSERT INTO foo (thingy, duration) VALUES (?, ?)',
thingy, seconds)
db.commit()
def print_timedelta_from_database(thingy):
cur = db.execute('SELECT duration FROM foo WHERE thingy = ?', thingy)
seconds = int(cur.fetchone()[0])
days, hours, minutes, seconds = seconds_to_dhms(seconds)
print '{} took {} minutes, {} hours, {} days'.format(thingy, minutes, hours, days)
A datetime.timedelta corresponds to the difference between two dates, not a date itself. It's only expressed in terms of days, seconds, and microseconds, since larger time units like months and years don't decompose cleanly (is 30 days 1 month or 0.9677 months?).
If you want to convert a timedelta into hours and minutes, you can use the total_seconds() method to get the total number of seconds and then do some math:
x = datetime.timedelta(1, 5, 41038) # Interval of 1 day and 5.41038 seconds
secs = x.total_seconds()
hours = int(secs / 3600)
minutes = int(secs / 60) % 60
There is no need for custom helper functions if all we need is to print the string of the form [D day[s], ][H]H:MM:SS[.UUUUUU]. timedelta object supports str() operation that will do this. It works even in Python 2.6.
>>> from datetime import timedelta
>>> timedelta(seconds=90136)
datetime.timedelta(1, 3736)
>>> str(timedelta(seconds=90136))
'1 day, 1:02:16'
I don't think it's a good idea to caculate yourself.
If you just want a pretty output, just covert it into str with str() function or directly print() it.
And if there's further usage of the hours and minutes, you can parse it to datetime object use datetime.strptime()(and extract the time part with datetime.time() mehtod), for example:
import datetime
delta = datetime.timedelta(seconds=10000)
time_obj = datetime.datetime.strptime(str(delta),'%H:%M:%S').time()
Just use strftime :)
Something like that:
my_date = datetime.datetime(2013, 1, 7, 10, 31, 34, 243366, tzinfo=<UTC>)
print(my_date.strftime("%Y, %d %B"))
After edited your question to format timedelta, you could use:
def timedelta_tuple(timedelta_object):
return timedelta_object.days, timedelta_object.seconds//3600, (timedelta_object.seconds//60)%60
# Try this code
from datetime import timedelta
class TimeDelta(timedelta):
def __str__(self):
_times = super(TimeDelta, self).__str__().split(':')
if "," in _times[0]:
_hour = int(_times[0].split(',')[-1].strip())
if _hour:
_times[0] += " hours" if _hour > 1 else " hour"
else:
_times[0] = _times[0].split(',')[0]
else:
_hour = int(_times[0].strip())
if _hour:
_times[0] += " hours" if _hour > 1 else " hour"
else:
_times[0] = ""
_min = int(_times[1])
if _min:
_times[1] += " minutes" if _min > 1 else " minute"
else:
_times[1] = ""
_sec = int(_times[2])
if _sec:
_times[2] += " seconds" if _sec > 1 else " second"
else:
_times[2] = ""
return ", ".join([i for i in _times if i]).strip(" ,").title()
# Test
>>> str(TimeDelta(seconds=10))
'10 Seconds'
>>> str(TimeDelta(seconds=60))
'01 Minute'
>>> str(TimeDelta(seconds=90))
'01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3000))
'50 Minutes'
>>> str(TimeDelta(seconds=3600))
'1 Hour'
>>> str(TimeDelta(seconds=3690))
'1 Hour, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3660))
'1 Hour, 01 Minute'
>>> str(TimeDelta(seconds=3630))
'1 Hour, 30 Seconds'
>>> str(TimeDelta(seconds=3600*20))
'20 Hours'
>>> str(TimeDelta(seconds=3600*20 + 3000))
'20 Hours, 50 Minutes'
>>> str(TimeDelta(seconds=3600*20 + 3630))
'21 Hours, 30 Seconds'
>>> str(TimeDelta(seconds=3600*20 + 3660))
'21 Hours, 01 Minute'
>>> str(TimeDelta(seconds=3600*20 + 3690))
'21 Hours, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24))
'1 Day'
>>> str(TimeDelta(seconds=3600*24 + 10))
'1 Day, 10 Seconds'
>>> str(TimeDelta(seconds=3600*24 + 60))
'1 Day, 01 Minute'
>>> str(TimeDelta(seconds=3600*24 + 90))
'1 Day, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24 + 3000))
'1 Day, 50 Minutes'
>>> str(TimeDelta(seconds=3600*24 + 3600))
'1 Day, 1 Hour'
>>> str(TimeDelta(seconds=3600*24 + 3630))
'1 Day, 1 Hour, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24 + 3660))
'1 Day, 1 Hour, 01 Minute'
>>> str(TimeDelta(seconds=3600*24 + 3690))
'1 Day, 1 Hour, 01 Minute, 30 Seconds'
>>> str(TimeDelta(seconds=3600*24*2))
'2 Days'
>>> str(TimeDelta(seconds=3600*24*2 + 9999))
'2 Days, 2 Hours, 46 Minutes, 39 Seconds'
I defined own helper function to convert timedelta object to 'HH:MM:SS' format - only hours, minutes and seconds, without changing hours to days.
def format_timedelta(td):
hours, remainder = divmod(td.total_seconds(), 3600)
minutes, seconds = divmod(remainder, 60)
hours, minutes, seconds = int(hours), int(minutes), int(seconds)
if hours < 10:
hours = '0%s' % int(hours)
if minutes < 10:
minutes = '0%s' % minutes
if seconds < 10:
seconds = '0%s' % seconds
return '%s:%s:%s' % (hours, minutes, seconds)
An alternative for this (older) question is to create a relative time from a timedelta converted to seconds. This can be accomplished using the time.gmtime(...) method that accepts seconds since the epoch:
>>> time.strftime("%H:%M:%S",time.gmtime(36901)) # secs = 36901
'10:15:01'
And, that's it! (NOTE: Here's a link to format specifiers for time.strftime() so the difference can be truncated to any units, as needed. ...)
Notably, this technique is also a great way to tell if your current time zone is actually in daylight savings time or not. (It provides an offset of 0 or 1 hours meaning it can be interpreted basically as a boolean.)
import datetime
import pytz
import time
pacific=pytz.timezone('US/Pacific')
now=datetime.datetime.now()
# pacific.dst(now).total_seconds() yields 3600 secs. [aka 1 hour]
time.strftime("%-H", time.gmtime(pacific.dst(now).total_seconds()))
'1'
This can be rendered to a method is_standard_time(...) where 1 means true and 0 means false.
Do you want to print the date in that format? This is the Python documentation: http://docs.python.org/2/library/datetime.html#strftime-strptime-behavior
>>> a = datetime.datetime(2013, 1, 7, 10, 31, 34, 243366)
>>> print a.strftime('%Y %d %B, %M:%S%p')
>>> 2013 07 January, 31:34AM
For the timedelta:
>>> a = datetime.timedelta(0,5,41038)
>>> print '%s seconds, %s microseconds' % (a.seconds, a.microseconds)
But please notice, you should make sure it has the related value. For the above cases, it doesn't have the hours and minute values, and you should calculate from the seconds.
datetime.timedelta(hours=1, minutes=10)
#python 2.7

Issues with displaying time results in Python

I have written a code to take in a running pace value (min/km), convert it to speed (km/hr) and then depending on the slope gradient and whether the direction of travel is up or downhill the lost speed is calculated (km/hr). The new running speed is then displayed along with the new running pace and the time your route is altered by.
The issue is when I input a pace such as 3:50 (min/km) with an uphill slope of 1% the new running pace is 3:60 (min/km). How do I get the script to tick over to 4:00 in this case? Also if 3:55 (min/km) is input the new running pace given is 4:5 (min/km) when it should read as 4:05 (min/km). How do i edit this?
The script is:
import math
print('Q1')
SurveyPace = input("Running Pace (min/km): \n "). split(":")
SurveyPace = float(SurveyPace[0])*60 + float(SurveyPace[1])
Speed = 3600/SurveyPace
print("Original running speed =","%.2f" % round(Speed,2), 'km/hr')
print("--------------------------------------------------------")
print('Q2')
SlopeDirection = int(input('For Uphill press 1 \nFor Downhill press 2 \n '))
print("--------------------------------------------------------")
print('Q3')
SlopeGradient = float(input('Percentage gradient(without the % symbol)?\n '))
print("--------------------------------------------------------")
print('CALCULATED RESULTS')
print("--------------------------------------------------------")
if SlopeDirection == 1:
Change = - 0.65 * SlopeGradient
if SlopeDirection == 2:
Change = + 0.35 * SlopeGradient
print ('This route alters your speed by \n', Change,'km/hr')
print("--------------------------------------------------------")
AdjustedSpeed = Speed + Change
AdjustedPace = 3600/AdjustedSpeed
PaceSecs = round(AdjustedPace % 60)
PaceMins = math.floor(AdjustedPace/60)
print("New running speed is \n","%.2f" % round(AdjustedSpeed,2), 'km/hr')
print("--------------------------------------------------------")
print("New running pace is \n", str(PaceMins) + ":" + str(PaceSecs), 'min/km')
print("--------------------------------------------------------")
print("This route alters your pace by \n", int(PaceSecs + (PaceMins*60)) - SurveyPace, "sec/km") #Prints the time change incured
print("--------------------------------------------------------")
Thanks
You can do this with the built-in function divmod:
# Round the AdjustedPace to seconds
AdjustedPace = round(3600/AdjustedSpeed)
minutes, seconds = divmod(AdjustedPace, 60)
print(minutes)
print(seconds)
This will lead to:
#Pace = 3:50
#4
#0
#Pace = 3:55
#4
#5
I would do this with timedelta objects from datetime:
import datetime
inp = raw_input('Enter your pace in minutes per km (min:km):')
mins, kms = inp.split(':')
time = datetime.timedelta(minutes=int(mins))
If you enter 60 minutes, for example, will give you:
> time
datetime.timedelta(0, 3600)
And then you can perform math operations on it and it stays correct:
> time / 2
datetime.timedelta(0, 1800)
Or if you want minutes just divide it by 60, hours divide it by 3600. You can also add and subtract timedelta objects from each other, or from datetime objects if you want timestamps. Or if your divisor leaves a remainder:
> new = time / 17
> new
datetime.timedelta(0, 3600)
> new.seconds
200
> new.microseconds
764706
Which you could then use to round if you wanted. It's a good way to make sure your time always stays accurate.

How do I convert seconds to hours, minutes and seconds?

I have a function that returns information in seconds, but I need to store that information in hours:minutes:seconds.
Is there an easy way to convert the seconds to this format in Python?
You can use datetime.timedelta function:
>>> import datetime
>>> str(datetime.timedelta(seconds=666))
'0:11:06'
By using the divmod() function, which does only a single division to produce both the quotient and the remainder, you can have the result very quickly with only two mathematical operations:
m, s = divmod(seconds, 60)
h, m = divmod(m, 60)
And then use string formatting to convert the result into your desired output:
print('{:d}:{:02d}:{:02d}'.format(h, m, s)) # Python 3
print(f'{h:d}:{m:02d}:{s:02d}') # Python 3.6+
I can hardly name that an easy way (at least I can't remember the syntax), but it is possible to use time.strftime, which gives more control over formatting:
from time import strftime
from time import gmtime
strftime("%H:%M:%S", gmtime(666))
'00:11:06'
strftime("%H:%M:%S", gmtime(60*60*24))
'00:00:00'
gmtime is used to convert seconds to special tuple format that strftime() requires.
Note: Truncates after 23:59:59
Using datetime:
With the ':0>8' format:
from datetime import timedelta
"{:0>8}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{:0>8}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{:0>8}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Without the ':0>8' format:
"{}".format(str(timedelta(seconds=66)))
# Result: '00:01:06'
"{}".format(str(timedelta(seconds=666777)))
# Result: '7 days, 17:12:57'
"{}".format(str(timedelta(seconds=60*60*49+109)))
# Result: '2 days, 1:01:49'
Using time:
from time import gmtime
from time import strftime
# NOTE: The following resets if it goes over 23:59:59!
strftime("%H:%M:%S", gmtime(125))
# Result: '00:02:05'
strftime("%H:%M:%S", gmtime(60*60*24-1))
# Result: '23:59:59'
strftime("%H:%M:%S", gmtime(60*60*24))
# Result: '00:00:00'
strftime("%H:%M:%S", gmtime(666777))
# Result: '17:12:57'
# Wrong
This is my quick trick:
from humanfriendly import format_timespan
secondsPassed = 1302
format_timespan(secondsPassed)
# '21 minutes and 42 seconds'
For more info Visit:
https://humanfriendly.readthedocs.io/en/latest/api.html#humanfriendly.format_timespan
The following set worked for me.
def sec_to_hours(seconds):
a=str(seconds//3600)
b=str((seconds%3600)//60)
c=str((seconds%3600)%60)
d=["{} hours {} mins {} seconds".format(a, b, c)]
return d
print(sec_to_hours(10000))
# ['2 hours 46 mins 40 seconds']
print(sec_to_hours(60*60*24+105))
# ['24 hours 1 mins 45 seconds']
A bit off topic answer but maybe useful to someone
def time_format(seconds: int) -> str:
if seconds is not None:
seconds = int(seconds)
d = seconds // (3600 * 24)
h = seconds // 3600 % 24
m = seconds % 3600 // 60
s = seconds % 3600 % 60
if d > 0:
return '{:02d}D {:02d}H {:02d}m {:02d}s'.format(d, h, m, s)
elif h > 0:
return '{:02d}H {:02d}m {:02d}s'.format(h, m, s)
elif m > 0:
return '{:02d}m {:02d}s'.format(m, s)
elif s > 0:
return '{:02d}s'.format(s)
return '-'
Results in:
print(time_format(25*60*60 + 125))
>>> 01D 01H 02m 05s
print(time_format(17*60*60 + 35))
>>> 17H 00m 35s
print(time_format(3500))
>>> 58m 20s
print(time_format(21))
>>> 21s
This is how I got it.
def sec2time(sec, n_msec=3):
''' Convert seconds to 'D days, HH:MM:SS.FFF' '''
if hasattr(sec,'__len__'):
return [sec2time(s) for s in sec]
m, s = divmod(sec, 60)
h, m = divmod(m, 60)
d, h = divmod(h, 24)
if n_msec > 0:
pattern = '%%02d:%%02d:%%0%d.%df' % (n_msec+3, n_msec)
else:
pattern = r'%02d:%02d:%02d'
if d == 0:
return pattern % (h, m, s)
return ('%d days, ' + pattern) % (d, h, m, s)
Some examples:
$ sec2time(10, 3)
Out: '00:00:10.000'
$ sec2time(1234567.8910, 0)
Out: '14 days, 06:56:07'
$ sec2time(1234567.8910, 4)
Out: '14 days, 06:56:07.8910'
$ sec2time([12, 345678.9], 3)
Out: ['00:00:12.000', '4 days, 00:01:18.900']
hours (h) calculated by floor division (by //) of seconds by 3600 (60 min/hr * 60 sec/min)
minutes (m) calculated by floor division of remaining seconds (remainder from hour calculation, by %) by 60 (60 sec/min)
similarly, seconds (s) by remainder of hour and minutes calculation.
Rest is just string formatting!
def hms(seconds):
h = seconds // 3600
m = seconds % 3600 // 60
s = seconds % 3600 % 60
return '{:02d}:{:02d}:{:02d}'.format(h, m, s)
print(hms(7500)) # Should print 02h05m00s
If you need to get datetime.time value, you can use this trick:
my_time = (datetime(1970,1,1) + timedelta(seconds=my_seconds)).time()
You cannot add timedelta to time, but can add it to datetime.
UPD: Yet another variation of the same technique:
my_time = (datetime.fromordinal(1) + timedelta(seconds=my_seconds)).time()
Instead of 1 you can use any number greater than 0. Here we use the fact that datetime.fromordinal will always return datetime object with time component being zero.
dateutil.relativedelta is convenient if you need to access hours, minutes and seconds as floats as well. datetime.timedelta does not provide a similar interface.
from dateutil.relativedelta import relativedelta
rt = relativedelta(seconds=5440)
print(rt.seconds)
print('{:02d}:{:02d}:{:02d}'.format(
int(rt.hours), int(rt.minutes), int(rt.seconds)))
Prints
40.0
01:30:40
Here is a way that I always use: (no matter how inefficient it is)
seconds = 19346
def zeroes (num):
if num < 10: num = "0" + num
return num
def return_hms(second, apply_zeroes):
sec = second % 60
min_ = second // 60 % 60
hrs = second // 3600
if apply_zeroes > 0:
sec = zeroes(sec)
min_ = zeroes(min_)
if apply_zeroes > 1:
hrs = zeroes(hrs)
return "{}:{}:{}".format(hrs, min_, sec)
print(return_hms(seconds, 1))
RESULT:
5:22:26
Syntax of return_hms() function
The return_hms() function is used like this:
The first variable (second) is the amount of seconds you want to convert into h:m:s.
The second variable (apply_zeroes) is formatting:
0 or less: Apply no zeroes whatsoever
1: Apply zeroes to minutes and seconds when they're below 10.
2 or more: Apply zeroes to any value (including hours) when they're below 10.
Here is a simple program that reads the current time and converts it to a time of day in hours, minutes, and seconds
import time as tm #import package time
timenow = tm.ctime() #fetch local time in string format
timeinhrs = timenow[11:19]
t=tm.time()#time.time() gives out time in seconds since epoch.
print("Time in HH:MM:SS format is: ",timeinhrs,"\nTime since epoch is : ",t/(3600*24),"days")
The output is
Time in HH:MM:SS format is: 13:32:45
Time since epoch is : 18793.335252338384 days
You can divide seconds by 60 to get the minutes
import time
seconds = time.time()
minutes = seconds / 60
print(minutes)
When you divide it by 60 again, you will get the hours
In my case I wanted to achieve format
"HH:MM:SS.fff".
I solved it like this:
timestamp = 28.97000002861023
str(datetime.fromtimestamp(timestamp)+timedelta(hours=-1)).split(' ')[1][:12]
'00:00:28.970'
The solutions above will work if you're looking to convert a single value for "seconds since midnight" on a date to a datetime object or a string with HH:MM:SS, but I landed on this page because I wanted to do this on a whole dataframe column in pandas. If anyone else is wondering how to do this for more than a single value at a time, what ended up working for me was:
mydate='2015-03-01'
df['datetime'] = datetime.datetime(mydate) + \
pandas.to_timedelta(df['seconds_since_midnight'], 's')
I looked every answers here and still tried my own
def a(t):
print(f"{int(t/3600)}H {int((t/60)%60) if t/3600>0 else int(t/60)}M {int(t%60)}S")
Results:
>>> a(7500)
2H 5M 0S
>>> a(3666)
1H 1M 6S
Python: 3.8.8
division = 3623 // 3600 #to hours
division2 = 600 // 60 #to minutes
print (division) #write hours
print (division2) #write minutes
PS My code is unprofessional

Categories