MCPcopy Create free account
hub / github.com/MaterializeInc/materialize / date_bin

Function date_bin

src/expr/src/scalar/func.rs:2018–2068  ·  view source on GitHub ↗
(
    stride: Interval,
    source: CheckedTimestamp<T>,
    origin: CheckedTimestamp<T>,
)

Source from the content-addressed store, hash-verified

2016}
2017
2018pub fn date_bin<T>(
2019 stride: Interval,
2020 source: CheckedTimestamp<T>,
2021 origin: CheckedTimestamp<T>,
2022) -> Result<CheckedTimestamp<T>, EvalError>
2023where
2024 T: TimestampLike,
2025{
2026 if stride.months != 0 {
2027 return Err(EvalError::DateBinOutOfRange(
2028 "timestamps cannot be binned into intervals containing months or years".into(),
2029 ));
2030 }
2031
2032 let stride_ns = match stride.duration_as_chrono().num_nanoseconds() {
2033 Some(ns) if ns <= 0 => Err(EvalError::DateBinOutOfRange(
2034 "stride must be greater than zero".into(),
2035 )),
2036 Some(ns) => Ok(ns),
2037 None => Err(EvalError::DateBinOutOfRange(
2038 format!("stride cannot exceed {}/{} nanoseconds", i64::MAX, i64::MIN,).into(),
2039 )),
2040 }?;
2041
2042 // Make sure the returned timestamp is at the start of the bin, even if the
2043 // origin is in the future. We do this here because `T` is not `Copy` and
2044 // gets moved by its subtraction operation.
2045 let sub_stride = origin > source;
2046
2047 let tm_diff = (source - origin.clone()).num_nanoseconds().ok_or_else(|| {
2048 EvalError::DateBinOutOfRange(
2049 "source and origin must not differ more than 2^63 nanoseconds".into(),
2050 )
2051 })?;
2052
2053 let remainder = tm_diff % stride_ns;
2054 let mut tm_delta = tm_diff - remainder;
2055
2056 if sub_stride && remainder != 0 {
2057 tm_delta = tm_delta.checked_sub(stride_ns).ok_or_else(|| {
2058 EvalError::DateBinOutOfRange(
2059 "source and origin must not differ more than 2^63 nanoseconds".into(),
2060 )
2061 })?;
2062 }
2063
2064 let res = origin
2065 .checked_add_signed(Duration::nanoseconds(tm_delta))
2066 .ok_or(EvalError::TimestampOutOfRange)?;
2067 Ok(CheckedTimestamp::from_timestamplike(res)?)
2068}
2069
2070// Non-monotone in `stride`: the result is `origin + floor((source - origin) /
2071// stride) * stride`. For a fixed source like `2024-01-01 12:00:00`, a 1-day

Callers 4

date_bin_timestampFunction · 0.85
date_bin_timestamp_tzFunction · 0.85
date_bin_timestampFunction · 0.85
date_bin_timestamp_tzFunction · 0.85

Calls 4

duration_as_chronoMethod · 0.80
checked_add_signedMethod · 0.80
cloneMethod · 0.45
checked_subMethod · 0.45

Tested by

no test coverage detected