def build_stop_timetable(
    feed: "Feed", stop_id: str, dates: List[str]
) -> DataFrame:
    """
    Return a DataFrame containing the timetable for the given stop ID
    and dates.

    Parameters
    ----------
    feed : Feed
    stop_id : string
        ID of the stop for which to build the timetable
    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 stop IDs are
        restricted to the given stop ID.
        The result is sorted by date then departure time.

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

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

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

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

    frames = []
    for date in dates:
        # Slice to stops active on date
        ids = a.loc[a[date] == 1, "trip_id"]
        f = t[t["trip_id"].isin(ids)].copy()
        f["date"] = date
        frames.append(f)

    f = pd.concat(frames)
    return f.sort_values(["date", "departure_time"])
Return a DataFrame containing the timetable for the given stop ID
    and dates.

    Parameters
    ----------
    feed : Feed
    stop_id : string
        ID of the stop for which to build the timetable
    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 stop IDs are
        restricted to the given stop ID.
        The result is sorted by date then departure time.

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

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