Related
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)
So i'm trying know in what time of day the man will end running. When in last line of code, trying to use an operator addition this error is popping out. What i'm doing wrong?
TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
import datetime
# first run, 1 mile
pace_minutes1 = 8
pace_seconds1 = 15
distance = 1 #1 mile
b = ((pace_minutes1 * 60) + pace_seconds1) * distance
print(b)
# second run, 3 mile
pace_minutes2 = 7
pace_seconds2 = 12
distance = 3 # 3 miles
a = ((pace_minutes2 * 60) + pace_seconds2) * distance
print(a)
# third run, 1 mile run
pace_minutes3 = 8
pace_seconds3 = 15
distance = 1 # 1 mile
c = ((pace_minutes3 * 60) + pace_seconds3) * distance
print(c)
x = (a + b + c)
print(x, "seconds")
time = datetime.timedelta(seconds=x) # converse value "x" seconds to time (h,m,s)
print("All running time will gonna take",time,"seconds") # total time spent running
start_time = datetime.time(6,52,0) # time from where he started running
print("The running started in",start_time)
end_time = (start_time + time) # time when he ended running
print(end_time)
You can only add the timedelta to a datetime.datetime object, not a datetime.time object (probably in order to avoid overflows).
So simple fix, use start_time = datetime.datetime(2021, 04, 21, 6,52,0)
Please find below answer .check if it what you desired.May be you can check stack overflow answer
import datetime
# first run, 1 mile
pace_minutes1 = 8
pace_seconds1 = 15
distance = 1 #1 mile
b = ((pace_minutes1 * 60) + pace_seconds1) * distance
print(b)
# second run, 3 mile
pace_minutes2 = 7
pace_seconds2 = 12
distance = 3 # 3 miles
a = ((pace_minutes2 * 60) + pace_seconds2) * distance
print(a)
# third run, 1 mile run
pace_minutes3 = 8
pace_seconds3 = 15
distance = 1 # 1 mile
c = ((pace_minutes3 * 60) + pace_seconds3) * distance
print(c)
x = (a + b + c)
print(x, "seconds")
time = datetime.timedelta(seconds=x) # converse value "x" seconds to time (h,m,s)
print("All running time will gonna take",time,"seconds") # total time spent running
start_time = datetime.time(6,52,0) # time from where he started running
# print(type(start_time))
# print(type(time))
print("The running started in",start_time)
end_time = (dt.datetime.combine(dt.date(1,1,1),start_time) + time).time()
print(end_time)
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.
Here is my convert_seconds function:
def convert_seconds(x):
hour = int(round(x / 3600))
minute = int(round(x / 60 - hour * 60))
second = int(round(x - (hour * 3600 + minute * 60), 1))
return str(hour) + ' hours, ' + str(minute) + ' minutes, ' + str(second) +' seconds'
When i run my function:
>>>print convert_seconds(7261.7)
2 hours, 1 minute, 1 seconds
it print out "1 second" instead of "1.7 second"
Why is that?
How can I fix that?
NOTE: Output I need is:
>>>print convert_seconds(7261.7)
2 hours, 1 minute, 1.7 seconds
Thanks.
Why is that?
Because you explicitly turn the result into an integer, removing anything beyond the decimal point:
second = int(round(x - (hour * 3600 + minute * 60), 1))
How can I fix that?
Don't turn the seconds result into an integer:
second = round(x - (hour * 3600 + minute * 60), 1)
You should not round the hour and minute calculations; you should be flooring the results instead; int() by itself does that for you. Drop the round() calls for those two values. The // floor division operator would give you the same result as calling int() on the division result, removing the need to round or floor explicitly.
You can use formatting operations to then only show the values as decimals:
>>> def convert_seconds(x):
... hour = x // 3600
... minute = x // 60 - hour * 60
... second = x - (hour * 3600 + minute * 60)
... return '{:.0f} hours, {:.0f} minutes, {:.1f} seconds'.format(hour, minute, second)
...
>>> convert_seconds(7261.7)
'2 hours, 1 minutes, 1.7 seconds'
To round a floating point value to 1 decimal but drop the .0 if that is what it was rounded to, you'll need to explicitly string off the .0:
>>> def convert_seconds(x):
... hour = x // 3600
... minute = x // 60 - hour * 60
... second = x - (hour * 3600 + minute * 60)
... second_formatted = format(second, '.1f').rstrip('0').rstrip('.')
... return '{:.0f} hours, {:.0f} minutes, {} seconds'.format(hour, minute, second_formatted)
...
>>> convert_seconds(7261.7)
'2 hours, 1 minutes, 1.7 seconds'
>>> convert_seconds(7261)
'2 hours, 1 minutes, 1 seconds'
The expression format(second, '.1f').rstrip('0').rstrip('.') formats the seconds value but removes any .0 by first stripping 0 followed by stripping the remaining ..
Instead of division and subtraction, you may want to use the divmod() function:
def convert_seconds(x):
minutes, seconds = divmod(x, 60)
hours, minutes = divmod(minutes, 60)
second_formatted = format(seconds, '.1f').rstrip('0').rstrip('.')
return '{:.0f} hours, {:.0f} minutes, {} seconds'.format(hours, minutes, second_formatted)
The divmod() function returns the result of the quotient and the remainder; divmod(x, 60) returns the number of minutes (number of times 60 fits in x), and the remainder seconds. Apply the same function again on the number of minutes, and you get hours and a minutes remainder.
I think you have other problems here too ;-) For example,
>>> print convert_seconds(3500.0)
1 hours, -2 minutes, 20 seconds
In general, you're often rounding when you should be truncating. This is easier to do working with integers, so the following separates the argument into integer and fractional parts, does most work with integers, and puts the fractional part back at the end (but only if needed - if it's not 0.0):
def convert_seconds(x):
from math import modf
frac, whole = modf(x)
hours, leftover = divmod(int(whole), 3600)
minutes, seconds = divmod(leftover, 60)
if frac:
seconds += frac # change to float to get fraction
return "{} hours, {} minutes, {} seconds".format(
hours, minutes, seconds)
for case in 3500.0, 7261.7, 7325:
print case, "->", convert_seconds(case)
That prints:
3500.0 -> 0 hours, 58 minutes, 20 seconds
7261.7 -> 2 hours, 1 minutes, 1.7 seconds
7325 -> 2 hours, 2 minutes, 5 seconds
When you turn a float type into an int type, it will discard all decimal values and gives you the barebones integer underneath it all.
Try this:
def convert_seconds(x):
hour = int(round(x / 3600))
minute = int(round(x / 60 - hour * 60))
second = float(round(x - (hour * 3600 + minute * 60), 1))
return str(hour) + ' hours, ' + str(minute) + ' minutes, ' + str(second) +' seconds'
print(convert_seconds(7261.7))
You added a comment underneath where you asked, "yes but what about "convert_seconds(7325)", then seconds will be 5.0 instead of 5 "
You can do something like that to fix this problem. After doing the assignment to second:
second = float(round(x - (hour * 3600 + minute * 60), 1))
Do this:
second == int(second) if second == int(second) else second
"i don't want it to be float (5.0) but i want it to be round to (1.666666 ~ 1.7, not 2). how can i do that?"
You already do that! Your second argument to round is 1 which automatically rounds it off to one decimal place. Try doing convert_seconds(7261.6666) and this code will work.
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