'''
    [begin, end)
    or
    [begin, infinity)  # if <end> == None
'''


class DatetimeInterval:
    def __init__(self, begin, end):
        assert begin is not None
        assert end is None or begin < end
        self.begin = begin
        self.end = end

    def to_string(self):
        ret_val = '[' + self.begin.isoformat() + ', '
        ret_val += 'Inf' if self.end is None else self.end.isoformat()
        ret_val += ')'
        return ret_val


def make_interval(start, end):
    # type: (datetime, Optional[datetime]) -> Optional[DatetimeInterval]
    if end is None or start < end:
        return DatetimeInterval(start, end)
    else:
        return None


def datetime_intervals_overlap(lhs, rhs):
    if lhs is None or rhs is None:
        return None

    latest_start = max(lhs.begin, rhs.begin)
    if lhs.end is not None and rhs.end is not None:
        earliest_end = min(lhs.end, rhs.end)
    elif lhs.end is not None:
        earliest_end = lhs.end
    elif rhs.end is not None:
        earliest_end = rhs.end
    else:
        earliest_end = None

    if earliest_end is None or latest_start < earliest_end:
        return DatetimeInterval(latest_start, earliest_end)
    else:
        return None
