@@ -27,6 +27,14 @@ const MIN_TIMESTAMP_SECONDS: i64 = 72_057_595;
2727// Maximum supported timestamp value in seconds (16 Mar 2242 12:56:31 GMT).
2828const MAX_TIMESTAMP_SECONDS : i64 = 8_589_934_591 ;
2929
30+ /// Builds the error returned when a Unix timestamp falls outside the range Quickwit supports.
31+ fn unsupported_timestamp_error ( timestamp : impl std:: fmt:: Display ) -> String {
32+ format ! (
33+ "failed to parse unix timestamp `{timestamp}`. Quickwit only supports timestamp values \
34+ ranging from `13 Apr 1972 23:59:55` to `16 Mar 2242 12:56:31`"
35+ )
36+ }
37+
3038pub fn parse_date_time_str (
3139 date_time_str : & str ,
3240 date_time_formats : & [ DateTimeInputFormat ] ,
@@ -76,6 +84,12 @@ pub fn parse_timestamp_float(
7684 . join( "`, `" )
7785 ) ) ;
7886 }
87+ // We apply the same range check as the integer path (`parse_timestamp`) to reject out-of-range
88+ // values instead of silently wrapping them when casting the `u128` nanoseconds to `i64`
89+ // below.
90+ if !( MIN_TIMESTAMP_SECONDS as f64 ..=MAX_TIMESTAMP_SECONDS as f64 ) . contains ( & timestamp) {
91+ return Err ( unsupported_timestamp_error ( timestamp) ) ;
92+ }
7993 let duration_since_epoch = Duration :: try_from_secs_f64 ( timestamp)
8094 . map_err ( |error| format ! ( "failed to parse datetime `{timestamp}`: {error}" ) ) ?;
8195 let timestamp_nanos = duration_since_epoch. as_nanos ( ) as i64 ;
@@ -167,10 +181,7 @@ pub fn parse_timestamp(timestamp: i64) -> Result<TantivyDateTime, String> {
167181 MIN_TIMESTAMP_NANOS ..=MAX_TIMESTAMP_NANOS => {
168182 Ok ( TantivyDateTime :: from_timestamp_nanos ( timestamp) )
169183 }
170- _ => Err ( format ! (
171- "failed to parse unix timestamp `{timestamp}`. Quickwit only support timestamp values \
172- ranging from `13 Apr 1972 23:59:55` to `16 Mar 2242 12:56:31`"
173- ) ) ,
184+ _ => Err ( unsupported_timestamp_error ( timestamp) ) ,
174185 }
175186}
176187
@@ -386,6 +397,15 @@ mod tests {
386397 `iso8601`, `rfc2822`"
387398 ) ;
388399 }
400+ {
401+ // Out-of-range float values used to silently wrap when casting `u128` nanoseconds to
402+ // `i64`. They must now be rejected, just like the integer path does.
403+ let error = parse_timestamp_float ( 9e18 , & [ DateTimeInputFormat :: Timestamp ] ) . unwrap_err ( ) ;
404+ assert ! ( error. contains( "failed to parse unix timestamp" ) , "{error}" ) ;
405+
406+ let error = parse_timestamp_float ( -1.0 , & [ DateTimeInputFormat :: Timestamp ] ) . unwrap_err ( ) ;
407+ assert ! ( error. contains( "failed to parse unix timestamp" ) , "{error}" ) ;
408+ }
389409 }
390410
391411 #[ test]
0 commit comments