def weighted_expiration(weights, contract_dates):
    """
    Calculate the days to expiration for generic futures, weighted by the
    composition of the underlying tradeable instruments.

    Parameters:
    -----------
    weights: pandas.DataFrame
        A DataFrame of instrument weights with a MultiIndex where the top level
        contains pandas.Timestamps and the second level is instrument names.
        The columns consist of generic names.
    contract_dates: pandas.Series
        Series with index of tradeable contract names and pandas.Timestamps
        representing the last date of the roll as values

    Returns:
    --------
    A pandas.DataFrame with columns of generic futures and index of dates.
    Values are the weighted average of days to expiration for the underlying
    contracts.

    Examples:
    ---------
    >>> import pandas as pd
    >>> import mapping.util as util
    >>> vals = [[1, 0, 1/2, 1/2, 0, 1, 0], [0, 1, 0, 1/2, 1/2, 0, 1]]
    >>> widx = pd.MultiIndex.from_tuples([(pd.Timestamp('2015-01-03'), 'CLF15'),
    ...                                   (pd.Timestamp('2015-01-03'), 'CLG15'),
    ...                                   (pd.Timestamp('2015-01-04'), 'CLF15'),
    ...                                   (pd.Timestamp('2015-01-04'), 'CLG15'),
    ...                                   (pd.Timestamp('2015-01-04'), 'CLH15'),
    ...                                   (pd.Timestamp('2015-01-05'), 'CLG15'),
    ...                                   (pd.Timestamp('2015-01-05'), 'CLH15')])
    >>> weights = pd.DataFrame({"CL1": vals[0], "CL2": vals[1]}, index=widx)
    >>> contract_dates = pd.Series([pd.Timestamp('2015-01-20'),
    ...                             pd.Timestamp('2015-02-21'),
    ...                             pd.Timestamp('2015-03-20')],
    ...                            index=['CLF15', 'CLG15', 'CLH15'])
    >>> util.weighted_expiration(weights, contract_dates)
    """  # NOQA
    cols = weights.columns
    weights = weights.reset_index(level=-1)
    expiries = contract_dates.to_dict()
    weights.loc[:, "expiry"] = weights.iloc[:, 0].apply(lambda x: expiries[x])
    diffs = (pd.DatetimeIndex(weights.expiry)
             - pd.Series(weights.index, weights.index)).apply(lambda x: x.days)
    weights = weights.loc[:, cols]
    wexp = weights.mul(diffs, axis=0).groupby(level=0).sum()
    return wexp