Add timezone information to a datetime object, only if it is naive.

    >>> make_tz_aware(datetime.datetime(2001, 9, 8, 7, 6))
    datetime.datetime(2001, 9, 8, 7, 6, tzinfo=<UTC>)
    >>> make_tz_aware(['2010-01-01'], 'PST')
    [datetime.datetime(2010, 1, 1, 0, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)]
    >>> make_tz_aware(['1970-10-31', '1970-12-25', '1971-07-04'], 'CDT')  # doctest: +NORMALIZE_WHITESPACE
    [datetime.datetime(1970, 10, 31, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1970, 12, 25, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1971,  7,  4, 0, 0, tzinfo=<DstTzInfo 'US/Central' CDT-1 day, 19:00:00 DST>)]
    >>> make_tz_aware([None, float('nan'), float('inf'), 1980, 1979.25*365.25, '1970-10-31',
    ...                '1970-12-25', '1971-07-04'],
    ...               'CDT')  # doctest: +NORMALIZE_WHITESPACE
    [None, nan, inf,
     datetime.datetime(6, 6, 3, 0, 0, tzinfo=<DstTzInfo 'US/Central' LMT-1 day, 18:09:00 STD>),
     datetime.datetime(1980, 4, 16, 1, 30, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1970, 10, 31, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1970, 12, 25, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1971, 7, 4, 0, 0, tzinfo=<DstTzInfo 'US/Central' CDT-1 day, 19:00:00 DST>)]
    >>> make_tz_aware(datetime.time(22, 23, 59, 123456))
    datetime.time(22, 23, 59, 123456, tzinfo=<UTC>)
    >>> make_tz_aware(datetime.time(22, 23, 59, 123456), 'PDT', is_dst=True)
    datetime.time(22, 23, 59, 123456, tzinfo=<DstTzInfo 'US/Pacific' LMT-1 day, 16:07:00 STD>)

def make_tz_aware(dt, tz='UTC', is_dst=None):
    """Add timezone information to a datetime object, only if it is naive.

    >>> make_tz_aware(datetime.datetime(2001, 9, 8, 7, 6))
    datetime.datetime(2001, 9, 8, 7, 6, tzinfo=<UTC>)
    >>> make_tz_aware(['2010-01-01'], 'PST')
    [datetime.datetime(2010, 1, 1, 0, 0, tzinfo=<DstTzInfo 'US/Pacific' PST-1 day, 16:00:00 STD>)]
    >>> make_tz_aware(['1970-10-31', '1970-12-25', '1971-07-04'], 'CDT')  # doctest: +NORMALIZE_WHITESPACE
    [datetime.datetime(1970, 10, 31, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1970, 12, 25, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1971,  7,  4, 0, 0, tzinfo=<DstTzInfo 'US/Central' CDT-1 day, 19:00:00 DST>)]
    >>> make_tz_aware([None, float('nan'), float('inf'), 1980, 1979.25*365.25, '1970-10-31',
    ...                '1970-12-25', '1971-07-04'],
    ...               'CDT')  # doctest: +NORMALIZE_WHITESPACE
    [None, nan, inf,
     datetime.datetime(6, 6, 3, 0, 0, tzinfo=<DstTzInfo 'US/Central' LMT-1 day, 18:09:00 STD>),
     datetime.datetime(1980, 4, 16, 1, 30, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1970, 10, 31, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1970, 12, 25, 0, 0, tzinfo=<DstTzInfo 'US/Central' CST-1 day, 18:00:00 STD>),
     datetime.datetime(1971, 7, 4, 0, 0, tzinfo=<DstTzInfo 'US/Central' CDT-1 day, 19:00:00 DST>)]
    >>> make_tz_aware(datetime.time(22, 23, 59, 123456))
    datetime.time(22, 23, 59, 123456, tzinfo=<UTC>)
    >>> make_tz_aware(datetime.time(22, 23, 59, 123456), 'PDT', is_dst=True)
    datetime.time(22, 23, 59, 123456, tzinfo=<DstTzInfo 'US/Pacific' LMT-1 day, 16:07:00 STD>)

    """
    # make sure dt is a datetime, time, or list of datetime/times
    dt = make_datetime(dt)
    if not isinstance(dt, (list, datetime.datetime, datetime.date, datetime.time, pd.Timestamp)):
        return dt
    # TODO: deal with sequence of timezones
    try:
        tz = dt.tzinfo or tz
    except (ValueError, AttributeError, TypeError):
        pass
    try:
        tzstr = str(tz).strip().upper()
        if tzstr in TZ_ABBREV_NAME:
            is_dst = is_dst or tzstr.endswith('DT')
            tz = TZ_ABBREV_NAME.get(tzstr, tz)
    except (ValueError, AttributeError, TypeError):
        pass
    try:
        tz = pytz.timezone(tz)
    except (ValueError, AttributeError, TypeError):
        # from traceback import print_exc
        # print_exc()
        pass
    try:
        return tz.localize(dt, is_dst=is_dst)
    except (ValueError, AttributeError, TypeError):
        # from traceback import print_exc
        # print_exc()  # TypeError: unsupported operand type(s) for +: 'datetime.time' and 'datetime.timedelta'
        pass
    # could be datetime.time, which can't be localized. Insted `replace` the TZ
    # don't try/except in case dt is not a datetime or time type -- should raise an exception
    if not isinstance(dt, list):
        return dt.replace(tzinfo=tz)

    return [make_tz_aware(dt0, tz=tz, is_dst=is_dst) for dt0 in dt]