rust 40 lines · 7 steps

Forward-filling a time series in Rust

Bucket known samples by time, then walk a fixed grid carrying the last seen value into gaps.

Explained by highlit
1use chrono::{DateTime, Duration, Utc};
2 
3#[derive(Debug, Clone)]
4pub struct Sample {
5 pub at: DateTime<Utc>,
6 pub value: Option<f64>,
7}
8 
9pub fn fill_forward(
10 samples: &[Sample],
11 start: DateTime<Utc>,
12 end: DateTime<Utc>,
13 step: Duration,
14) -> Vec<Sample> {
15 let mut by_bucket = std::collections::BTreeMap::new();
16 for s in samples {
17 if let Some(v) = s.value {
18 let bucket = s.at.timestamp() - s.at.timestamp() % step.num_seconds();
19 by_bucket.insert(bucket, v);
20 }
21 }
22 
23 let mut out = Vec::new();
24 let mut carried: Option<f64> = None;
25 let mut cursor = start;
26 
27 while cursor <= end {
28 let bucket = cursor.timestamp() - cursor.timestamp() % step.num_seconds();
29 if let Some(&v) = by_bucket.get(&bucket) {
30 carried = Some(v);
31 }
32 out.push(Sample {
33 at: cursor,
34 value: carried,
35 });
36 cursor += step;
37 }
38 
39 out
40}
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1Snapping timestamps to fixed buckets lets you align irregular samples onto a regular grid.
  2. 2A single carried value threaded through the loop cheaply propagates the last known reading into gaps.
  3. 3Leading gaps before any real sample stay None, which is the honest result when nothing is known yet.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Forward-filling a time series in Rust — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code