def _create_lagged_data_by_intersecting_times(
    target_series: TimeSeries,
    output_chunk_length: int,
    output_chunk_shift: int,
    past_covariates: Optional[TimeSeries],
    future_covariates: Optional[TimeSeries],
    sample_weight: Optional[TimeSeries],
    lags: Optional[Sequence[int]],
    lags_past_covariates: Optional[Sequence[int]],
    lags_future_covariates: Optional[Sequence[int]],
    max_samples_per_ts: Optional[int],
    multi_models: bool,
    check_inputs: bool,
    is_training: bool,
    stride: int,
    show_warnings: bool = True,
) -> tuple[
    np.ndarray,
    Optional[np.ndarray],
    Union[pd.RangeIndex, pd.DatetimeIndex],
    Optional[np.ndarray],
]:
    """
    Helper function called by `_create_lagged_data` that computes `X`, `y`, and `times` by
    first finding the time points in each series that *could* be used to create features/labels,
    and then finding which of these 'available' times is shared by all specified series. The lagged
    values are then extracted by finding the index of each of these 'shared times' in each series,
    and then offsetting this index by the requested lag value (if constructing `X`) or the requested
    `output_chunk_length` (if constructing `y`). This approach is used if we *cannot* assume that the
    specified series are of the same frequency.
    """
    feature_times, min_lags, _ = _get_feature_times(
        target_series=target_series,
        past_covariates=past_covariates,
        future_covariates=future_covariates,
        lags=lags,
        lags_past_covariates=lags_past_covariates,
        lags_future_covariates=lags_future_covariates,
        output_chunk_length=output_chunk_length,
        output_chunk_shift=output_chunk_shift,
        is_training=is_training,
        return_min_and_max_lags=True,
        check_inputs=check_inputs,
        show_warnings=show_warnings,
    )
    if check_inputs:
        series_and_lags_not_specified = [min_lag is None for min_lag in min_lags]
        if all(series_and_lags_not_specified):
            raise_log(
                ValueError("Must specify at least one series-lags pair."), logger=logger
            )
        if not (isinstance(stride, int) and stride > 0):
            raise_log(
                ValueError("`stride` must be a positive integer greater than 0."),
                logger=logger,
            )
    sample_weight_vals = _extract_sample_weight(sample_weight, target_series)
    shared_times = get_shared_times(*feature_times, sort=True)
    if shared_times is None:
        raise_log(
            ValueError(
                "Specified series do not share any common times for which features can be created."
            ),
            logger=logger,
        )
    if stride > 1:
        # calculate the starting index so that the last element is included after applying the stride
        # equivalent to shared_times[::-stride][::-1]
        shared_times = shared_times[(len(shared_times) - 1) % stride :: stride]
    if len(shared_times) > max_samples_per_ts:
        shared_times = shared_times[-max_samples_per_ts:]
    X = []
    shared_time_idx = None
    label_shared_time_idx = None
    for i, (series_i, lags_i, min_lag_i) in enumerate(
        zip(
            [target_series, past_covariates, future_covariates],
            [lags, lags_past_covariates, lags_future_covariates],
            min_lags,
        )
    ):
        series_and_lags_specified = min_lag_i is not None
        is_target_series = is_training and (i == 0)
        if series_and_lags_specified or is_target_series:
            time_index_i = series_i.time_index
            add_to_start = (not is_target_series) and (
                time_index_i[0] > shared_times[0]
            )
            add_to_end = (not is_target_series) and (
                time_index_i[-1] < shared_times[-1]
            )
            if add_to_start or add_to_end:
                new_start = shared_times[0] if add_to_start else None
                new_end = shared_times[-1] if add_to_end else None
                num_prepended = (
                    (time_index_i[0] - shared_times[0]) // series_i.freq
                    if add_to_start
                    else 0
                )
                time_index_i = _extend_time_index(
                    time_index_i, series_i.freq, new_start=new_start, new_end=new_end
                )
            else:
                num_prepended = 0
            shared_time_idx = (
                np.searchsorted(time_index_i, shared_times).reshape(-1, 1)
                - num_prepended
            )
        if series_and_lags_specified:
            idx_to_get = shared_time_idx + np.array(lags_i, dtype=int)
            # Before reshaping: lagged_vals.shape = (n_observations, num_lags, n_components, n_samples)
            lagged_vals = series_i.all_values(copy=False)[idx_to_get, :, :]
            # After reshaping: lagged_vals.shape = (n_observations, num_lags*n_components, n_samples)
            lagged_vals = lagged_vals.reshape(
                lagged_vals.shape[0], -1, lagged_vals.shape[-1]
            )
            X.append(lagged_vals)
        # `target_series` indices required for creating labels:
        if is_target_series:
            label_shared_time_idx = shared_time_idx
    X = np.concatenate(X, axis=1)
    if is_training:
        if multi_models:
            # All points between time `t` and `t + output_chunk_length - 1` are labels:
            idx_to_get = (
                label_shared_time_idx
                + np.arange(output_chunk_length)
                + output_chunk_shift
            )
        else:
            # Only point at time `t + output_chunk_length - 1` is a label:
            idx_to_get = (
                label_shared_time_idx + output_chunk_length + output_chunk_shift - 1
            )

        # extract target labels and sample weights
        y_and_weights = []
        for vals in [target_series.all_values(copy=False), sample_weight_vals]:
            if vals is None:
                y_and_weights.append(None)
                continue

            # Before reshaping: lagged_vals.shape = (n_observations, num_lags, n_components, n_samples)
            vals = vals[idx_to_get, :, :]
            # After reshaping: lagged_vals.shape = (n_observations, num_lags*n_components, n_samples)
            vals = vals.reshape(vals.shape[0], -1, vals.shape[-1])
            y_and_weights.append(vals)
        y, weights = y_and_weights
    else:
        y, weights = None, None
    return X, y, shared_times, weights

    Helper function called by `_create_lagged_data` that computes `X`, `y`, and `times` by
    first finding the time points in each series that *could* be used to create features/labels,
    and then finding which of these 'available' times is shared by all specified series. The lagged
    values are then extracted by finding the index of each of these 'shared times' in each series,
    and then offsetting this index by the requested lag value (if constructing `X`) or the requested
    `output_chunk_length` (if constructing `y`). This approach is used if we *cannot* assume that the
    specified series are of the same frequency.
    
darts/utils/data/tabularization/tabularization.py