7
\$\begingroup\$

Given a string in a 24 hour format the program outputs a 12 hour format. The rules are:

  • The output format must be 'hh:mm a.m.' if it represents before midday and 'hh:mm p.m.' after midday
  • When the hour is less than 10:00 you should not write a 0 before the hour, example: '9:05 a.m.'

For example:

12:30 → 12:30 p.m.
09:00 → 9:00 a.m.
23:15 → 11:15 p.m.

The code:

import datetime
def time_converter(time):
 midday_dt = datetime.datetime.strptime('12:00','%H:%M')
 time_dt = datetime.datetime.strptime(time, '%H:%M')
 if time_dt >= midday_dt:
 if time_dt >= datetime.datetime.strptime('13:00','%H:%M'):
 hours, minutes = clamp_to_twelve(time_dt, midday_dt)
 time = f'{hours}:{minutes}'
 time += ' p.m.'
 else:
 if time_dt < datetime.datetime.strptime('10:00','%H:%M'):
 time = time[1:]
 if is_midnight(time_dt):
 hours, minutes = clamp_to_twelve(time_dt, midday_dt)
 time = f'{hours}:{minutes:02d}'
 time += ' a.m.'
 return time
def clamp_to_twelve(time_dt, midday_dt):
 clamp_dt = time_dt - midday_dt
 minutes, seconds = divmod(clamp_dt.seconds, 60)
 hours, minutes = divmod(minutes, 60)
 return [hours, minutes]
def is_midnight(time_dt):
 return (time_dt >= datetime.datetime.strptime('00:00','%H:%M') and
 time_dt <= datetime.datetime.strptime('00:59','%H:%M'))
if __name__ == '__main__':
 assert time_converter('12:30') == '12:30 p.m.'
 assert time_converter('09:00') == '9:00 a.m.'
 assert time_converter('23:15') == '11:15 p.m.'
200_success
145k22 gold badges190 silver badges478 bronze badges
asked May 26, 2019 at 8:12
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

To help with readability, I'd just import datetime.datetime and then alias it, that way you aren't typing datetime.datetime all over the place:

from datetime import datetime as dt
def time_converter(time):
 midday_dt = dt.strptime('12:00','%H:%M')
 time_dt = dt.strptime(time, '%H:%M')
 if time_dt >= midday_dt:
 if time_dt >= dt.strptime('13:00','%H:%M'):
 hours, minutes = clamp_to_twelve(time_dt, midday_dt)
 time = f'{hours}:{minutes}'
 time += ' p.m.'
 else:
 if time_dt < dt.strptime('10:00','%H:%M'):
 time = time[1:]
 if is_midnight(time_dt):
 hours, minutes = clamp_to_twelve(time_dt, midday_dt)
 time = f'{hours}:{minutes:02d}'
 time += ' a.m.'
 return time
def clamp_to_twelve(time_dt, midday_dt):
 clamp_dt = time_dt - midday_dt
 minutes, seconds = divmod(clamp_dt.seconds, 60)
 hours, minutes = divmod(minutes, 60)
 return [hours, minutes]
def is_midnight(time_dt):
 return (time_dt >= dt.strptime('00:00','%H:%M') and
 time_dt <= dt.strptime('00:59','%H:%M'))
if __name__ == '__main__':
 assert time_converter('12:30') == '12:30 p.m.'
 assert time_converter('09:00') == '9:00 a.m.'
 assert time_converter('23:15') == '11:15 p.m.'

Next, if you are just unpacking the list returned from clamp_to_twelve, I would just return a tuple:

def clamp_to_twelve(time_dt, midday_dt):
 clamp_dt = time_dt - midday_dt
 minutes, seconds = divmod(clamp_dt.seconds, 60)
 hours, minutes = divmod(minutes, 60)
 return hours, minutes

This saves you from having to construct the list, as well as the additional overhead of over-allocating memory to take into account the mutable list.

As a last optimization, you could refactor your if statements to not be nested. Because you are using if if rather than if elif, all of your statements are executed within the nested blocks:

def time_converter(time):
 midday_dt = dt.strptime('12:00','%H:%M')
 time_dt = dt.strptime(time, '%H:%M')
 if time_dt >= dt.strptime('13:00', '%H:%M'):
 hours, minutes = clamp_to_twelve(time_dt, midday_dt)
 time = f'{hours}:{minutes} p.m.'
 elif time_dt > midday_dt:
 time += ' p.m.'
 elif time_dt < dt.strptime('10:00', '%H:%M'):
 time = f'{time[1:]} a.m.'
 elif is_midnight(time_dt):
 hours, minutes = clamp_to_twelve(time_dt, midday_dt)
 time = f'{hours}:{minutes} a.m.'
 else:
 time += ' a.m.'
 return time

The only issue being that the order is quite important, since time_dt > midday_dt and time_dt >= dt.strptime('13:00', '%H:%M') are not mutually exclusive. However, you do get a slight time bump because of the separation of blocks of code:

python -m timeit -s "from file import time_converter, time_converter_2; times = ['12:30', '09:00', '11:15']" '(time_converter(t) for t in times)'
1000000 loops, best of 3: 0.275 usec per loop
python -m timeit -s "from file import time_converter, time_converter_2; times = ['12:30', '09:00', '11:15']" '(time_converter_2(t) for t in times)'
1000000 loops, best of 3: 0.277 usec per loop

Emphasis on slight. Depends on what you find more readable.

Toby Speight
87.2k14 gold badges104 silver badges322 bronze badges
answered Jul 2, 2019 at 20:59
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.