Time Calculator solution with OOP approach

Hello fellows!
I just finished the Time Calculator challenge using OOP approach. I represented the final result as a sum of instances of two classes: Time and Duration.
What do you think, if this approach make sense? And may be you have an idea how it could be optimized?
My code herebellow under the spoiler:

class Time:
    weekdays = ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Sunday"]

    def __init__(self, start, weekday):
        start_parts = [start.split(':')[0]]
        start_parts.extend(start.split(':')[1].split())
        self.start = int(start_parts[0]) * 60 + int(start_parts[1])
        if start_parts[2] == 'PM' and int(start_parts[0]) < 12:
            self.start += 12 * 60
        elif start_parts[2] == 'AM' and int(start_parts[0]) == 12:
            self.start -= 12 * 60
        self.weekday = weekday.title() if weekday is not None else weekday

    def __add__(self, other):
        days_gone = 0
        days_gone_string = ''
        if isinstance(other, Duration):
            total_minutes = self.start + other.dur
            if  24 * 60 < total_minutes < 2 * 24 * 60:
                days_gone = 1
                days_gone_string = ' (next day)'
                total_minutes %= 24 * 60
            elif total_minutes > 24 * 60:
                days_gone = total_minutes // (24 * 60)
                days_gone_string = f' ({days_gone} days later)'
                total_minutes %= 24 * 60

            h = total_minutes // 60
            m = total_minutes % 60
            if h < 12:
                period = 'AM'
                if h == 0:
                    h = 12
            else:
                period = 'PM'
                if h > 12:
                    h -= 12

            if self.weekday is not None:
                new_weekday = self.weekdays[(self.weekdays.index(self.weekday) + days_gone) % 7]
                return f'{h}:{str(m).zfill(2)} {period}, {new_weekday}' + days_gone_string

        return f'{h}:{str(m).zfill(2)} {period}' + days_gone_string           


class Duration:
    def __init__(self, dur):
        dur_parts = dur.split(':')
        self.dur = int(dur_parts[0]) * 60 + int(dur_parts[1])


def add_time(start, duration, day=None):
    return Time(start, day) + Duration(duration)

As far as using it for practicing classes basics and trying some advanced behavior like adding ability to use + with custom classes, this is great.

Some considerations should be given whether there’s need for classes here (not really), or if the classes behave the way it might be expected - when used individually or together. For example, the most sticking out:

  • Time class can be added to Duration, but Time cannot be added to Time, nor Duration to Duration.
  • Adding Time to Duration results in a string. More natural seem to be new Time instance, with modified data.
    Generally all this is making a bit hard to use these classes for anything else than very specific use case - adding Time and Duration.

There’s fantastic Python related talk from Jack Diederich called Stop Writing Classes.

2 Likes