If I interpret what the OP wants correctly, we can compute the time to the next nearest crossing (either up or down) for each element in t
using:
dt <- outer(-t,c(tzcd_h,tzcu_h),"+")
dt[dt < 0] <- Inf
dt_cross <- do.call(pmin.int, as.data.frame(dt))
Notes:
- Use
outer
to compute the difference in time between each crossing and each t
. The result of this is a matrix where each row corresponds to an element in t
, each column corresponds to a crossing, and each element of this matrix is the time difference.
- We are only interested in positive time differences (i.e., to the next crossing), so we set all negative values in the matrix to
Inf
.
- Finally, we compute the minimum time difference for each row (i.e., each element in
t
) using a fast method for performing row-wise min
of a matrix as detailed in this SO answer.
- If the requirement is to compute the time difference to just the next up crossing (and not the next either up or down), then replace
c(tzcd_h,tzcu_h)
with tzcu_h
in the outer
computation. Similarly, if the requirement is to compute the time difference to just the next down crossing, then replace c(tzcd_h,tzcu_h)
with tzcd_h
in the outer
computation. Obviously, we can also compute both of these separately.
The resulting dt_cross
is a vector of the same length as t
that contains the minimum time to the next crossing. This vector can be added to the df
using df$dt_cross <- dt_cross
.
head(dt_cross)
##[1] 0.6354627 0.5854627 0.5354627 0.4854627 0.4354627 0.3854627
We can plot this dt_cross
as blue dots overlaid on the plot generated by the OP's code to see what is happening:
points(t,dt_cross,col="blue",pch='.')

Note that the last 20 values of dt_cross
are Inf
. This is because the last crossing found is before these 20 values of t
.
Update to new requirements
By definition, a distance is a metric and is non-negative. In the following we distinguish time distance from time difference, which can be either positive, zero, or negative. If we are interested in computing the time distance to the nearest down crossing, then the computation is:
dt_n <- dt_p <- outer(-t,tzcd_h,"+")
dt_p[dt_p < 0] <- Inf
dt_cross_p <- do.call(pmin.int, as.data.frame(dt_p))
dt_n[dt_n > 0] <- -Inf
dt_cross_n <- do.call(pmax.int, as.data.frame(dt_n))
dt_cross <- ifelse(dt_cross_p < -dt_cross_n, dt_cross_p, dt_cross_n)
Notes:
- Use
outer
as before to compute the time difference matrix between each down crossing and each element in t
. We set this result to both dt_n
and dt_p
.
dt_p
will be use to find the minimum positive time difference to a down crossing point for each element in t
. We set all its negative values to Inf
and compute its row-wise minimum as before. The result is a vector dt_cross_p
, which can be interpreted as being the minimum time distance to the next down crossing for each element in t
.
- Conversely,
dt_n
will be use to find the maximum negative time difference to a down crossing point for each element in t
. We set all its positive values to -Inf
and call pmax
likewise. The result is a vector dt_cross_n
, which can be interpreted as being the minimum time distance (maximum negative time difference) to the previous down crossing for each element in t
.
- The time difference to the nearest down crossing for each element in
t
is then its corresponding element in dt_cross_p
if dt_cross_p < -dt_cross_n
and dt_cross_n
, otherwise. We make this computation in vectorized fashion using ifelse
.
We now have the plot:
