def convert_time_or_go_back(date, date_type):
    """Convert a single date to a new date_type (cftime.datetime or pd.Timestamp).

    If the new date is invalid, it goes back a day and tries again. If it is still
    invalid, goes back a second day.

    This is meant to convert end-of-month dates into a new calendar.
    """
    if date_type == pd.Timestamp:
        date_type = default_precision_timestamp
    try:
        return date_type(
            date.year,
            date.month,
            date.day,
            date.hour,
            date.minute,
            date.second,
            date.microsecond,
        )
    except OutOfBoundsDatetime:
        raise
    except ValueError:
        # Day is invalid, happens at the end of months, try again the day before
        try:
            return date_type(
                date.year,
                date.month,
                date.day - 1,
                date.hour,
                date.minute,
                date.second,
                date.microsecond,
            )
        except ValueError:
            # Still invalid, happens for 360_day to non-leap february. Try again 2 days before date.
            return date_type(
                date.year,
                date.month,
                date.day - 2,
                date.hour,
                date.minute,
                date.second,
                date.microsecond,
            )
Convert a single date to a new date_type (cftime.datetime or pd.Timestamp).

    If the new date is invalid, it goes back a day and tries again. If it is still
    invalid, goes back a second day.

    This is meant to convert end-of-month dates into a new calendar.
    
xarray/coding/times.py