@@ -114,7 +114,12 @@ pub fn expected_time_bins(
114114 let first_bin_start =
115115 DateTime :: from_timestamp ( first_bin_start, 0 ) . ok_or ( TimeBinError :: IntervalOutOfRange ) ?;
116116
117- ( 0 ..num_bins)
117+ let seconds_to_cover = time_range. end . timestamp ( ) - first_bin_start. timestamp ( ) ;
118+ let bins_to_cover_range = ( seconds_to_cover + bin_seconds_i64 - 1 ) / bin_seconds_i64;
119+ let bins_to_cover_range =
120+ u64:: try_from ( bins_to_cover_range) . map_err ( |_| TimeBinError :: IntervalOutOfRange ) ?;
121+
122+ ( 0 ..bins_to_cover_range)
118123 . map ( |i| {
119124 let offset = i64:: try_from ( i)
120125 . ok ( )
@@ -123,13 +128,10 @@ pub fn expected_time_bins(
123128 let bin_start = first_bin_start
124129 . checked_add_signed ( chrono:: Duration :: seconds ( offset) )
125130 . ok_or ( TimeBinError :: IntervalOutOfRange ) ?;
126- let bin_end = if i == num_bins - 1 {
127- time_range. end
128- } else {
129- bin_start
130- . checked_add_signed ( chrono:: Duration :: seconds ( bin_seconds_i64) )
131- . ok_or ( TimeBinError :: IntervalOutOfRange ) ?
132- } ;
131+ let next_bin_start = bin_start
132+ . checked_add_signed ( chrono:: Duration :: seconds ( bin_seconds_i64) )
133+ . ok_or ( TimeBinError :: IntervalOutOfRange ) ?;
134+ let bin_end = next_bin_start. min ( time_range. end ) ;
133135 Ok ( ( bin_start. to_rfc3339 ( ) , bin_end. to_rfc3339 ( ) ) )
134136 } )
135137 . collect ( )
@@ -576,10 +578,24 @@ mod tests {
576578
577579 let bins = expected_time_bins ( & time_range, 2 ) . unwrap ( ) ;
578580
581+ assert_eq ! ( bins. len( ) , 3 ) ;
579582 assert_eq ! ( bins[ 0 ] . 0 , "2023-01-01T12:00:00+00:00" ) ;
580583 assert_eq ! ( bins[ 0 ] . 1 , "2023-01-01T12:05:00+00:00" ) ;
581584 assert_eq ! ( bins[ 1 ] . 0 , "2023-01-01T12:05:00+00:00" ) ;
582- assert_eq ! ( bins[ 1 ] . 1 , "2023-01-01T12:12:00+00:00" ) ;
585+ assert_eq ! ( bins[ 1 ] . 1 , "2023-01-01T12:10:00+00:00" ) ;
586+ assert_eq ! ( bins[ 2 ] . 0 , "2023-01-01T12:10:00+00:00" ) ;
587+ assert_eq ! ( bins[ 2 ] . 1 , "2023-01-01T12:12:00+00:00" ) ;
588+ }
589+
590+ #[ test]
591+ fn expected_time_bins_covers_full_range_when_start_is_mid_bin ( ) {
592+ let time_range = time_period_from_str ( "2026-06-01T05:56:00Z" , "2026-06-04T05:56:00Z" ) ;
593+
594+ let bins = expected_time_bins ( & time_range, 60 ) . unwrap ( ) ;
595+
596+ assert_eq ! ( bins. len( ) , 61 ) ;
597+ assert_eq ! ( bins. last( ) . unwrap( ) . 0 , "2026-06-04T04:48:00+00:00" ) ;
598+ assert_eq ! ( bins. last( ) . unwrap( ) . 1 , "2026-06-04T05:56:00+00:00" ) ;
583599 }
584600
585601 #[ test]
0 commit comments