def build_route_timetable(
    feed: "Feed", route_id: str, dates: List[str]
) -> DataFrame:
    """
    Return a timetable for the given route and dates.

    Parameters
    ----------
    feed : Feed
    route_id : string
        ID of a route in ``feed.routes``
    dates : string or list
        A YYYYMMDD date string or list thereof

    Returns
    -------
    DataFrame
        The columns are all those in ``feed.trips`` plus those in
        ``feed.stop_times`` plus ``'date'``, and the trip IDs
        are restricted to the given route ID.
        The result is sorted first by date and then by grouping by
        trip ID and sorting the groups by their first departure time.

        Skip dates outside of the Feed's dates.

        If there is no route activity on the given dates, then return
        an empty DataFrame.

    Notes
    -----
    Assume the following feed attributes are not ``None``:

    - ``feed.stop_times``
    - Those used in :func:`.trips.get_trips`

    """
    dates = feed.restrict_dates(dates)
    if not dates:
        return pd.DataFrame()

    t = pd.merge(feed.trips, feed.stop_times)
    t = t[t["route_id"] == route_id].copy()
    a = feed.compute_trip_activity(dates)

    frames = []
    for date in dates:
        # Slice to trips active on date
        ids = a.loc[a[date] == 1, "trip_id"]
        f = t[t["trip_id"].isin(ids)].copy()
        f["date"] = date
        # Groupby trip ID and sort groups by their minimum departure time.
        # For some reason NaN departure times mess up the transform below.
        # So temporarily fill NaN departure times as a workaround.
        f["dt"] = f["departure_time"].fillna(method="ffill")
        f["min_dt"] = f.groupby("trip_id")["dt"].transform(min)
        frames.append(f)

    f = pd.concat(frames)
    return f.sort_values(["date", "min_dt", "stop_sequence"]).drop(
        ["min_dt", "dt"], axis=1
    )
Return a timetable for the given route and dates.

    Parameters
    ----------
    feed : Feed
    route_id : string
        ID of a route in ``feed.routes``
    dates : string or list
        A YYYYMMDD date string or list thereof

    Returns
    -------
    DataFrame
        The columns are all those in ``feed.trips`` plus those in
        ``feed.stop_times`` plus ``'date'``, and the trip IDs
        are restricted to the given route ID.
        The result is sorted first by date and then by grouping by
        trip ID and sorting the groups by their first departure time.

        Skip dates outside of the Feed's dates.

        If there is no route activity on the given dates, then return
        an empty DataFrame.

    Notes
    -----
    Assume the following feed attributes are not ``None``:

    - ``feed.stop_times``
    - Those used in :func:`.trips.get_trips`