I am trying to write a simple calculator to calculate how fast my battery will drain from 100% to 0% by taking a time and percentage for start and subtracting it from the finish time and percentage.
I was able to make a quick and dirty script to accomplish this, but I am learning OOP, and I would like some feedback on how to improve my code and implement OOP for this task. I added in some verbose print statements to make it easier for me to remember what everything is when I run it, and I intend to wrap it up into a simple bash script or maybe implement tkinter for GUI.
Any thoughts or suggestions will help! My main environment is python 3, but I added the error handling for those who run with python2 because it doesn't like a preceding 0 in the time number.
from datetime import timedelta
# Getting inputs for time and percentage
try:
start_time = str(input('What is the starting time in 24 hour time? Format: HHMM >> '))
start_time_hr = start_time[:2]
start_time_min = start_time[2:]
except SyntaxError:
print('Try entering the time again without the preceding 0. \n')
start_time = str(input('What is the starting time in 24 hour time? Format: HHMM >> '))
start_time_hr = start_time[0]
start_time_min = start_time[1:]
start_perc = int(input('What is the starting battery percentage? >> '))
try:
end_time = str(input('What is the finish time in 24 hour time? Format: HHMM >> '))
end_time_hr = end_time[:2]
end_time_min = end_time[2:]
except SyntaxError:
print('Try entering the time again without the preceding 0. \n')
end_time = str(input('What is the finish time in 24 hour time? Format: HHMM >> '))
end_time_hr = end_time[0]
end_time_min = end_time[1:]
end_perc = int(input('What is the ending battery percentage? >> '))
# Turning numbers into times for calculation
start = timedelta(hours=int(start_time_hr), minutes=int(start_time_min))
end = timedelta(hours=int(end_time_hr), minutes=int(end_time_min))
# Calculating and printing the results
perc_difference = float(-(end_perc - start_perc))
time_difference = end - start
time_difference_minute = time_difference.total_seconds() / 60
discharge = (100.0 * time_difference_minute / perc_difference) / 60
print()
print()
print('*****')
print('Percentage Difference = ' + str(perc_difference))
print('Minutes Passed = ' + str(time_difference.total_seconds() / 60))
print('100% to 0% in ~' + str(round(discharge, 2)) + ' hours.')
print('*****')
print()
print()
print()
I don't think this program will benefit from using OOP.
That said; I do have a few notes on style and lack of defensive programming.
First; You do not need to wrap an input call with str, since it returns a string by default.
Second; You have wrapped a couple of your input calls with int, which is perfectly fine, but these need to be wrapped in try blocks as any input that cannot be converted to an integer will raise a ValueError.
Third; You should NEVER be handling a syntax error in that way. If you're getting syntax errors, fix the code, don't try to wrap it with a bandaid.
Fourth; You do not need to write that many print statements.
The entire print block could be rewritten as follows:
print('*****\nPercentage Difference = ' + str(perc_difference) + 'Minutes Passed = ' + str(time_difference.total_seconds() / 60)) + "\n100% to 0% in ~' + str(round(discharge, 2)) + ' hours.\n' +
*****')
Or, in my opinion; the much more readable fstring variant:
msg = f"*****\nPercentage Difference = {perc_difference}\nMinutes Passed = {time_difference.total_seconds() / 60}\n100% to 0% in ~{round(discharge,2)} hours.\n"
print( msg )
Related
I am trying to make a clock that stops at a certain time. This is the code I currently have:
import time as t
import datetime as dt
import os
tc = input("When do you want this to stop? (military time please) ")
exit = False
date = str(dt.datetime.now().date())
while (exit == False):
if dt.datetime.now() == date + " " + tc + ":00.0000":
exit = True
else:
print(dt.datetime.now())
t.sleep(0.01)
os.system('cls')
The problem is that the time never exactly gets to the perfect place for the parts less than a second so how do I get it to stop?
do you mean like this?
if dt.datetime.now() >= date + " " + tc + ":00.0000"
also please format the datetime.now() to the string you want
using something like datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
You could check if the time has passed, something like
if dt.datetime.now() >= date + " " + tc + ":00.0000":
You'll probably have to fiddle with the available methods to get it to work, I don't know if there's a built in comparator in that library. But something along those lines just checking if the current time is past the desired time.
Good Evening,
I am trying to estimate the remaining time to the end of a loop; I've used:
start = datetime.now()
progress = 0
for i in range(1000):
#do a few calculations
progress += 1
stop = datetime.now()
execution_time = stop-start
remaining = execution_time * ( 1000 - progress )
print("Progress:", progress, "%, estimated", remaining, "time remaining")
But it does not seem to work properly, since it goes up to minutes, even though the loop would take 20 seconds in total, and decrease quickly when reaching the end.
How can I try to forecast the remaining time of a loop efficiently and correctly?
Simply use tqdm package:
from tqdm import tqdm
for i in tqdm(range(10000)):
dosomthing()
It will print everything for you:
76%|█████████████ | 7568/10000 [00:33<00:10, 229.00it/s]
Rather than using datetime.datetime.now() for this sort of thing you can use time.perf_counter(), which is available in Python 3.3+. From the docs:
Return the value (in fractional seconds) of a performance counter,
i.e. a clock with the highest available resolution to measure a short
duration. It does include time elapsed during sleep and is
system-wide. The reference point of the returned value is undefined,
so that only the difference between the results of consecutive calls
is valid.
Also, you can print using a carriage return instead of a newline so that the progress reports are printed on a single line. Here's a brief demo derived from your code.
from time import sleep, perf_counter
fmt = " Progress: {:>3}% estimated {:>3}s remaining"
num = 1000
start = perf_counter()
for i in range(1, num + 1):
# Simulate doing a few calculations
sleep(0.01)
stop = perf_counter()
remaining = round((stop - start) * (num / i - 1))
print(fmt.format(100 * i // num, remaining), end='\r')
print()
Depending on your terminal (and Python version) you may also need to add the flush=True keyword arg to the print call in order to get the progress reports to print as they are issued.
I think that in this line:
remaining = execution_time * ( 1000 - progress )
you should divide execution_time/progress, because you want to know how long it takes to complete one percent of progress.
remaining = execution_time/progress * ( 1000 - progress )
Your calculation for time remaining is wrong. If it takes execution_time for progress steps. Then how much does it take for 1000 steps ?
Simple cross multiply gives you the total time. Subtract it from the time already elapsed and that will give you the time remaining.
remaining_time = execution_time * 1000 / progress - execution_time
percent_complete = (progress / 1000) * 100 #You can simplify this if you like
print("Progress:", percent_complete , "%, Estimated", remaining_time, "time remaining")
Also your variable execution_time_1 is never defined
I need to make a simple program which converts a 24 hour time which is input, into 12 hour time, which produces an error if an incorrect time is put in. I currently have the code below, however, I have a few issues. One issue is that if "0924" is input, it outputs "924 am", when I need it to produce "9:24am" (the space isn't hugely important but it's preferred). Also, I'm not entirely sure where to start for doing 0001-0059, because "0001" for example produces "1 am", which is obviously incorrect.
print("Enter a time in 24 hour time, e.g. '1620'")
time = (int(input("Time: ")))
normal = 0
if (time == 0000):
normal="12:00am"
print (normal)
elif (time>1200):
normal = (time - 1200)
print (int(normal), ("pm"))
elif (time<1200):
normal = time
print (int(normal), ("am"))
Thanks in advance for any help!
Try this
import time
timevalue_24hour = "1620";
timevalue_24hour = timevalue_24hour[:2] + ':' + timevalue_24hour[2:]
print (timevalue_24hour)
t = time.strptime(timevalue_24hour, "%H:%M")
timevalue_12hour = time.strftime( "%I:%M %p", t )
print (timevalue_12hour)
Take input as a string. Assign it to timevalue_24hour and rest will work
When printing, normal is just a number. The 0s disappear because you don't write 0s in front of numbers normally. I would suggest doing something like this
def normal_check(num):
if num < 10:
return "000"+str(num)
elif num < 100:
return "00"+str(num)
elif num < 1000:
return "0"+str(num)
else:
return str(num)
print("Enter a time in 24 hour time, e.g. '1620'")
time = (int(input("Time: ")))
normal = 0
if (time == 0000):
normal="12:00am"
print (normal)
elif (time>1200):
normal = normal_check(time - 1200)
print (normal, ("pm"))
elif (time<1200):
normal = normal_check(time)
print (normal, ("am"))
The best way to do this will be to take the input as an str rather than int. Take it in as str and split it into two int values of two digits.
Then the first string if less than 12 will be hour else subtract 12 from first str and use PM. Also, the second str will just be minutes.
I am trying to make a basic wage timer for my brother who just got a job... What I wanted to have was a while loop running the code waiting for someone to press enter (or some other key) ends the loop and give the current wage. I was hoping to KeyboardInterrupt but if there is an easier way to do it I would love to hear about it. How could I do this?
a keyboard interrupt is generated only when someone hits ctrl-C or similar.
it sounds like your plan was to have code something like:
from time import sleep
wage = 0
try:
while True:
wage = wage + hourly_rate
sleep(60 * 60) # an hour in seconds
except KeyboardInterrupt:
print('you earned', wage)
and then have someone hit ctrl-C? which would work with a try/except. but if you want someone just to hit the return key then instead of adding things up, do some maths:
from time import time
start = time() # time in seconds from some arbitrary date in 1970 (it's a standard)
input('hit return to get your wage!')
end = time()
elapsed = end - start # time that has passed in seconds between start and end
wage = hourly_rate * elapsed / (60 * 60) # convert from hourly
print('you earned', wage)
the first version is a bit optimistic as it adds each hour at the start. the second is more accurate.
ps congrats to your brother!
No clue why this is happening. I must be missing something obvious.
I'm trying to make a counter print out something like SMPTE code (hours:minutes:seconds:frames (assuming 24fps)).
Code thus far:
import time
s_time = time.time()
def format_time():
t = time.time() - s_time
if t < 1:
print '00:00:00:%02d' % int(t/0.041666666666666664)
elif t < 60:
t = str(t).split('.')
print '00:00:%02d:%02d' % (int(t[0]), int(int(t[1][:4])/0.041666666666666664) )
while True:
format_time()
All seems well initially, until the duration surpasses 1 second and the elif branch is entered. Seconds print out fine, but the frames print out the full multi-digit result of the calculation. Given that the formatting operator is specifying %02d, just like it does in the first if branch (which behaves as expected), why is it not obeying in the second branch? I'm at a loss trying to figure out why it is still printing the full result rather than the truncated version.
You are trying to get the integer part and the fractional part of the float to print your result. It is a good practice to use operators and functions on numeric data directly instead of adding a heavy overhead by converting the float into str and back to number.
Use the math module modf function for that. It will also simplify your algorithm.
import time
import math
s_time = time.time()
def format_time():
t = time.time() - s_time
if t < 60:
f,i = math.modf(t)
print '00:00:%02d:%02d' % (i, f/0.041666666666666664)
while True:
format_time()
PS: for your code error, in your elif block, you are passing t as an integer with a huge value instead of passing the 0.xxxxx value of it. This error wouldn't occur if you keep using the math functions of floats.
I expect you want something like this:
hours = int(t)/3600
minutes = (int(t)/60)%60
seconds = int(t)%60
frames = (t-int(t))*24
print '%02d:%02d:%02d:%02d' % (hours, minutes, seconds, frames)
%02d means: print the integer and if it's shorter than 2 digits, prefix it with zeroes.
it doesn't limit the formatted string to two digits.
edit: one way of getting the first 2 (rounded) digits of a number n would be:
n = 13900
print round(n/10**math.floor(math.log10(n)-1))
or if you don't care about rounding, just cut the string...