def join_adjacent_intervals(intervals):
    """Join adjacent or overlapping intervals into contiguous intervals.

    Args:
        intervals (list of 2-element iterables): A list of iterables with 2
            elements where each such iterable (eg. the tuple (start, end))
            defines the start and end of the interval.

    Returns:
        list of list: Contiguous intervals.

    Examples:
        >>> join_adjacent_intervals([[1, 2], [2, 3], [-1, 1]])
        [[-1, 3]]
        >>> from datetime import datetime
        >>> contiguous = join_adjacent_intervals([
        ...     (datetime(2000, 1, 1), datetime(2000, 2, 1)),
        ...     (datetime(1999, 1, 1), datetime(2000, 1, 1)),
        ...     (datetime(1995, 1, 1), datetime(1995, 2, 1))
        ...     ])
        >>> contiguous == [
        ...     [datetime(1995, 1, 1), datetime(1995, 2, 1)],
        ...     [datetime(1999, 1, 1), datetime(2000, 2, 1)],
        ...     ]
        True
        >>> overlapping_contiguous = join_adjacent_intervals([
        ...     (datetime(1999, 1, 1), datetime(2000, 2, 1)),
        ...     (datetime(2000, 1, 1), datetime(2000, 2, 1)),
        ...     (datetime(1995, 1, 1), datetime(1995, 3, 1)),
        ...     (datetime(1995, 2, 1), datetime(1995, 4, 1)),
        ...     (datetime(1995, 4, 1), datetime(1995, 5, 1)),
        ...     ])
        >>> overlapping_contiguous == [
        ...     [datetime(1995, 1, 1), datetime(1995, 5, 1)],
        ...     [datetime(1999, 1, 1), datetime(2000, 2, 1)],
        ...     ]
        True
        >>> join_adjacent_intervals([]) == []
        True

    """
    if not intervals:
        return []
    intervals = list(map(list, intervals))
    sorted_intervals = sorted(intervals, key=lambda x: x[0])
    contiguous_intervals = [sorted_intervals.pop(0)]
    while sorted_intervals:
        if sorted_intervals[0][0] <= contiguous_intervals[-1][1]:
            contiguous_intervals[-1][1] = max(
                [sorted_intervals.pop(0)[1], contiguous_intervals[-1][1]]
            )
        else:
            contiguous_intervals.append(sorted_intervals.pop(0))
    return contiguous_intervals