Converting 12 hour clock time to 24 hour clock time - python

I know there are lot of answers available on the S/O web, but i am experiencing an unusual error in the HackerRank python 3 shell with the below code which works fine in Jupyter notebook.
time1=input()
l=time1.split(':')
if 'PM' in l[2]:
l[0]=int(l[0])+12
l[2]=l[2].rstrip('PM')
elif 'AM' in l[2]:
l[2]=l[2].rstrip('AM')
if l[0]=='12':
l[0]="0"
time2=''
for i in range(2):
time2+=str(l[i])+':'
time2+=l[2]
print(time2)
This is the challenge:
Given a time in 12-hour AM/PM format, convert it to military (24-hour)
time.
Note:
12:00:00AM on a 12-hour clock is 00:00:00 on a 24-hour clock.
12:00:00PM on a 12-hour clock is 12:00:00 on a 24-hour clock.
Example
s = '12:01:00PM'
Return '12:01:00'.
s = '12:01:00AM'
Return '00:01:00'.
Function Description
Complete the timeConversion function in the editor below. It should
return a new string representing the input time in 24 hour format.
timeConversion has the following parameter(s):
string s: a time in 12 hour format
Returns
string: the time in 12 hour format
Input Format
A single string s that represents a time in 12-hour clock format
(i.e.: hh:mm:ssAM or hh:mm:ssPM).
Constraints
All input times are valid
Sample Input 0
07:05:45PM
Sample Output 0
19:05:45
I did try to run the same cases which gave errors on the H/R but worked alright on the J/P notebook.
P.S. I know this might be a super basic question I've come up with but please pardon me, I am still a newbie :)

There seem to be two issues:
When the input has 12:00:00PM, your code returns an invalid result (24:00:00). It should in that case leave the 12 untouched.
When the input has 12:00:00AM, your code returns the hour with only 1 digit, while 2 are required.
So change this:
l[0] = int(l[0]) + 12
to:
if l[0] != "12":
l[0] = int(l[0]) + 12
And change this:
l[0] = "0"
to:
l[0] = "00"
With that it will work. Note that you are asked to write the body of the timeConversion function, so you should not have a hardcoded time1= in your code.
The final code could be like this:
def timeConversion(time1):
h = time1[0:2]
if time1[-2:] == "PM'":
if h != "12":
h = str(int(h) + 12)
elif h == '12':
h = "00"
return h + time1[2:-2]

def conv24(time):
"""
Converts 12HR clock to 24HR clock
time should be either
'hh:mm:ssAM' or 'hh:mm:ssPM'
"""
l = time.split(':')
if 'PM' in l[2]:
v = int(l[0])
if v < 12 and v > 0:
v += 12
l[0] = str(v)
l[2] = l[2].strip('PM')
elif 'AM' in l[2]:
v = int(l[0])
if v == 12:
l[0] = '00'
l[2] = l[2].strip('AM')
res = ''
for i in l:
res += i + ":"
return res.rstrip(':')

Related

How to convert the following time format to a time formatted string (HH:MM:SS)

I am reading the following kind of data from a file. The time is written like this there:
Is there a way I can convert the above string to the format 'HH:MM:SS'.I do not want a time object. It should return me a string.
I tried stripping the letters H and M but some data fields do not have H specified with them, so I could not figure out any other way to solve this problem.
Any help is welcome.
You could do it like this:
from datetime import datetime
try:
print(datetime.strptime("10H5M", "%HH%MM").strftime("%H:%M:%S"))
except ValueError:
try:
print(datetime.strptime("10H", "%HH").strftime("%H:%M:%S"))
except ValueError:
print(datetime.strptime("5M", "%MM").strftime("%H:%M:%S"))
view the formatting here, you could also use the str.find method instead of using try and except. Note the find method return -1 if not found and 0 if found so it would look something like:
from datetime import datetime
time_str = "10H5M"
if (time_str.find("H") + 1):
if (time_str.find("M") + 1):
print(datetime.strptime("10H5M", "%HH%MM").strftime("%H:%M:%S"))
else:
print(datetime.strptime("10H", "%HH").strftime("%H:%M:%S"))
else:
print(datetime.strptime("5M", "%MM").strftime("%H:%M:%S"))
instr = "24H45M"
hour = "00"
minute = "00"
second = "00"
arr = list(instr)
start = 0
for i, char in enumerate(arr):
if char == "H":
hour = int(''.join(arr[start:i]))
start=i+1
if char == "M":
minute = int(''.join(arr[start:i]))
start=i+1
if char == "S":
second = int(''.join(arr[start:i]))
start=i+1
print(f"{hour}:{minute}:{second}")
You can user re.search to extract numbers and str.zfill to add leading zeroes
import re
def format_time(s):
hours = 0
m = re.search(r'(\d+)H', s)
if m:
hours = m.group(1)
minutes = 0
m = re.search(r'(\d+)M', s)
if m:
minutes = m.group(1)
seconds = 0
m = re.search(r'(\d+)S', s)
if m:
seconds = m.group(1)
return f"{str(hours).zfill(2)}:{str(minutes).zfill(2)}:{str(seconds).zfill(2)}"
print(format_time("24H45M"))
print(format_time("35M"))
print(format_time("15M16S"))

How can I compare times (expressed as minutes and hours) correctly?

current_hour = 12
current_minute = 37
current_section = "PM"
due_hour = 9
due_minute = 0
due_section = "AM"
Given the current time and deadline time represented by the
variables above, determine if an assignment is still eligible
for submission. An assignment is eligible if the time
represented by current_hour, current_minute, and
current_section is before the time represented by due_hour,
due_minute, and due_section.
my code is
total_min_cur=((current_hour*60)+current_minute)
total_min_due=((due_hour*60)+due_minute)
print((total_min_cur<=total_min_due) and (due_section >= current_section) )
We tested your code with due_minute = 0, current_hour = 12, current_minute = 37, due_section = "AM", due_hour = 9, current_section = "AM". We expected your code to print this:
True
However, it printed this:
False
Try to convert the solution in 24 hour clock and then compare the result.
When both due_section and current_section are equal for your case. Your program will be correct for all total_min_cur and total_min_due until 11:59. After that your program is considering total_min_cur > total_min_due but in actuality it is reverse.
Kunal is correct. 12:01 AM is much earlier than 1:01 AM on a clock. In military time it 00:01 versus 01:01. Here's what you should do to account for that.
total_min_cur = (current_hour % 12) * 60 + current_minute
total_min_due = (due_hour % 12) * 60 + due_minute
print(current_section < due_section or (current_section == due_section and current_time < due_time))
This will help to solve it
current_hour = 12
current_minute = 37
current_section = "PM"
due_hour = 9
due_minute = 0
due_section = "AM"
if current_section=="AM" and current_hour==12:
current_time_24=0+current_minute
# print(current_time_24)
elif current_section=="AM":
current_time_24=current_hour*60+current_minute
# print(current_time_24)
elif current_section=="PM":
current_time_24=(current_hour+12)*60+current_minute
# print(current_time_24)
if due_section=="AM" and due_hour==12:
due_time_24=0+due_minute
# print(due_time_24)
elif due_section=="AM":
due_time_24=due_hour*60+due_minute
# print(due_time_24)
elif due_section=="PM":
due_time_24=(due_hour+12)*60+due_minute
# print(due_time_24)
print(current_time_24<due_time_24)
first of all current_hour<=due_hour -> 12<=9 is False
and you are using >= to strings. AM is not greater than PM(on alphabetical ordering). So False and False is False
Second you are comparing strings that is dangerous, because:
In [1]: "am" < "pm"
Out[1]: True
In [2]: "am" < "Pm"
Out[2]: False
You should do this print((total_min_cur>total_min_due) and (due_section < current_section) ) and you will get True.
Change due_section and current_section to something useful like enumerative , object or a boolean (es: morning=True ).
Or atleast do convert to the same case s.lower()

Calculating Sun Angle Code

My goal with this code was to write a code that measures the degree measure of the sun having that at 6:00 the angle is 0 and at 18:00 the angle is 180 degrees. I tried to make the time input a string and then loop through its characters and pick out the integers and put it into the list that way I could avoid the colon. It seems that this is still a problem. Can someone explain to me what's wrong with this code? Why do I keep getting an "unsupported operand type error"?
def sun_angle(time):
lis = []
time = str(time)
for i in time:
if i.isdigit():
lis.append(i)
else:
continue
a = int(lis[0]*10 + lis[1] + ((lis[2] + lis[3])/60))
b = a - 6
if b < 6 or b > 18:
return "I can't see the sun!"
else:
return b * 15
print(sun_angle("12:12"))
Michael's answer is a great explanation for why what you're doing isn't working (need to convert string to int before manipulating with * and +).
However, there are a lot of ways to parse the time that will be easier to work with than what you're doing here. I'd consider splitting and then parsing the two parts, or you could use the datetime library for more complexity:
# option 1
def parse_time_as_hour(time_str):
hour_str, min_str = time_str.split(':')
return int(hour_str) + int(min_str) / 60.0
# option 2
import datetime
def parse_time_as_hour(time_str):
parsed = datetime.datetime.strptime(time_str, '%H:%M')
return parsed.hour + parsed.minute / 60.0
def sun_angle(time):
fractional_hour = parse_time_as_hour(time)
if fractional_hour < 6 or fractional_hour >= 18:
return "I can't see the sun!"
else:
return (fractional_hour - 6) * 15
If you change the above similar line to:
a = int(lis[0]) * 10 + int(lis[1]) + ((int(lis[2]) + int(lis[3]))/60)
then you get a result. The problem on that line is that you're mixing int and str types. And since you're already passing in a string you can change time = str(time) to time = time. Casting time to a string is redundant.
Your error line is:
a = int(lis[0]*10 + lis[1] + ((lis[2] + lis[3])/60))
since time is a string type
def sun_angle(time):
lis = []
time = str(time)
for i in time:
if i.isdigit():
lis.append(int(i)) #cast it to type int
else:
continue
a = int(lis[0]*10 + lis[1] + ((lis[2] + lis[3])/60))
b = a - 6
if b < 0 or b >= 12:
return "I can't see the sun!"
else:
return b * 15
print(sun_angle("12:12"))
output: 90
You need to cast lis[i] to integer when you're calculating the value of a. 07:00 means sun is up, your logic fails and 18:01 means sun is down.
def sun_angle(time_):
lis = []
time_ = str(time_)
for i in time_:
if i.isdigit():
lis.append(i)
else:
continue
a = int(lis[0])*10
a += int(lis[1])
bb = (int(lis[2])*10 + int(lis[3]))
#print a
#print bb
#b = a - 6
if (a < 6 or a > 18) or (a == 18 and bb > 0):
return "I can't see the sun!"
else:
return (float(a)-6.0) * 15.0 + (15.0*float(bb))/60.0

Developing a function to show time without imports

def show_time(hour,min):
hour = int(input())
min = ''
for hour in (hour,min):
while 24 >= hour > 12:
hour -= 12
min == min
return hour, ":" min,'pm'
if hour < 12:
if 0 <= min <= 59
hour == hour
min == min
return hour, ":" min,'am'
So this is my code so far.^^
When I run this code, i keep getting an infinite loop for one... another thing is.. I feel like i am totally off. Btw.. I am trying to do this without importing anything and using the string formatting method. Please HELP!
Here were my instructions...
def show_time(hour,min): Accept integers for the hour (values from 0 to 23) and the minute
(values from 0 to 59). Construct the correct clock representation, such as the examples below.
o you must use the format method.
o Examples:
! show_time(9,15) → "9:15am"
! show_time(0,0) → "12:00am"
! show_time(12,0) → "12:00pm"
! show_time(22,5) → "10:05pm"
I can't get what you're trying to achieve using loops, but here's a simple solution.
def show_time(hour, minutes):
if hour >= 12:
suffix = "pm"
if hour != 12:
hour -= 12
else:
suffix = "am"
if hour == 0:
hour = 12
return "{0}:{1:02}{2}".format(hour, minutes, suffix)
Hope it helps.
Correct code should be like this:
def show_time(hour,min):
hour = int(hour)
min = int(min)
if hour > 12:
hour -= 12
return str(hour) + ":" + str(min) + 'pm'
else:
return str(hour) + ":" + str(min) + 'am'
print show_time(9,15)
You should think on simple level. For and while loops are unnecessary.
How about this:
def show_time(hour, min):
if hour > 24 or min > 59 or hour < 0 or min < 0:
raise ValueError("Invalid input")
# which half of day is this?
is_pm = (hour / 12.0) > 1
# normalize time in 0 to 11
hour = hour % 12
# get the correct half of day readable form
half_day = "pm" if is_pm else "am"
# print it out
print "%02d:%02d%s" % (hour, min, half_day)
Always try too keep things simple when possible, loops are useful but try to question whether they are really necessary.

Python timedelta issue with negative values

Hi I need some help to understand why this is happening.
I have a method to track 'time remaining' in an event program:
def get_program_time_budget(self):
return self.estimated_duration-self.get_program_duration()
All fine when the estimated_duration > self.get_program_duration() but when this goes the other way things get funny.
Results are displayed to the user:
Estimated 11 hours Allocated 10 hours 55 minutes Remaining 5 minutes
When the result goes negative it does this:
Estimated 11 hours Allocated 11 hours 5 minutes Remaining -1 day 23 hours 55 minutes
Any ideas how to get the result -5 minutes?
Here is the timedelta formatter (Note this is a Django filter, so receives the timedelta value as a str - but it is stored as a timedelta):
def format_duration(value):
try:
delim = ':'
toks = value.split(',')
hour = minute = ''
d_string = value.count('day') and toks[0] or ''
h, m, s = d_string and toks[-1].strip().split(delim) or value.split(delim)
try:
hour = int(h)
except:
pass
try:
minute = int(m)
except:
pass
h_string = "%s%s%s" % (hour and hour or '', (hour and ' hour' or ''),(hour and hour > 1 and 's' or '') )
m_string = "%s%s%s" % (minute and minute or '', (minute and ' minute' or ''),(minute and minute > 1 and 's' or ''))
return "%s %s %s" % (d_string, h_string, m_string)
except Exception, e:
logging.error("Error in format_duration -> %s. Duration value=%s" % (e, value))
return ''v
If you are using Python 2.7 or higher you can use timedelta.total_seconds() to get a float representation of the timedelta as a positive or negative number of seconds.
>>> datetime.timedelta(-1, 86100).total_seconds()
-300.0
You should be able to use this to calculate a number of minutes fairly easily.
If you are not using Python 2.7 you can use the following equivalent formula from the docs:
(td.microseconds + (td.seconds + td.days * 24 * 3600) * 10**6) / 10.0**6
Edit: It looks like you are probably using the default string representation for timedelta to display the result, so my original answer may not be as useful. I would suggest something like this for displaying the result:
def get_program_time_budget(self):
td = self.estimated_duration-self.get_program_duration()
if td.days < 0:
return '-' + str(datetime.timedelta() - td)
return str(td)
This would now return a string instead of a timedelta, and for negative timedeltas it would prepend a '-' to a positive timedelta.
Why?
Possibly as a unintended side effect of the way // and % are defined.
Possibly because it makes it easier to implement the datetime class. Five minutes before the epoch is 23:55, not 0:-5.
It doesn't really matter. Just know that it's how days, seconds, and microseconds get normalized. And that it can easily be worked around.
def format_timedelta(td):
if td < timedelta(0):
return '-' + format_timedelta(-td)
else:
# Change this to format positive timedeltas the way you want
return str(td)
>>> format_timedelta(timedelta(minutes=-5))
'-0:05:00'
Also if you are facing problems with a timedelta object containing negative values even though the values should be positive, you can use pythons builtin abs(td_object)
>>> current_time = datetime.datetime.now()
>>> fifteen_seconds = datetime.timedelta(seconds=15)
>>> time_delta_after_calculations = current_time - (current_time + fifteen_seconds) # It should give a timedelta with 15 seconds but it does not
>>> time_delta_after_calculations
datetime.timedelta(days=-1, seconds=86385)
>>> # The above is kind of True but not what expected (A day contains 86400 seconds)
>>> abs(time_delta_after_calculations) # Gives expected output
datetime.timedelta(seconds=15)

Categories

Resources