@@ -87,6 +87,16 @@ pub fn parse_time_to_unix(input: &str) -> Result<i64> {
8787 Ok ( parse_time_to_unix_millis ( input) ? / 1000 )
8888}
8989
90+ /// Parses a time string into a `chrono::DateTime<Utc>`.
91+ ///
92+ /// Returns an `anyhow` error if the input cannot be parsed or if the resulting
93+ /// timestamp falls outside chrono's representable range.
94+ pub fn parse_time_to_datetime ( input : & str ) -> Result < chrono:: DateTime < Utc > > {
95+ let ms = parse_time_to_unix_millis ( input) ?;
96+ chrono:: DateTime :: from_timestamp_millis ( ms)
97+ . ok_or_else ( || anyhow:: anyhow!( "timestamp out of valid range: {input:?}" ) )
98+ }
99+
90100/// Parses a human-readable duration string into milliseconds.
91101///
92102/// Unlike `parse_time_to_unix_millis`, this does **not** subtract from the
@@ -229,6 +239,43 @@ mod tests {
229239 assert ! ( parse_time_to_unix_millis( "" ) . is_err( ) ) ;
230240 }
231241
242+ #[ test]
243+ fn test_parse_time_to_datetime_relative ( ) {
244+ let dt = parse_time_to_datetime ( "1h" ) . unwrap ( ) ;
245+ let expected = Utc :: now ( ) . timestamp ( ) - 3600 ;
246+ assert ! ( ( dt. timestamp( ) - expected) . abs( ) < 2 ) ;
247+ }
248+
249+ #[ test]
250+ fn test_parse_time_to_datetime_long_form ( ) {
251+ let dt = parse_time_to_datetime ( "2hours" ) . unwrap ( ) ;
252+ let expected = Utc :: now ( ) . timestamp ( ) - 7200 ;
253+ assert ! ( ( dt. timestamp( ) - expected) . abs( ) < 2 ) ;
254+ }
255+
256+ #[ test]
257+ fn test_parse_time_to_datetime_unix_millis ( ) {
258+ let dt = parse_time_to_datetime ( "1700000000000" ) . unwrap ( ) ;
259+ assert_eq ! ( dt. timestamp_millis( ) , 1700000000000 ) ;
260+ }
261+
262+ #[ test]
263+ fn test_parse_time_to_datetime_rfc3339 ( ) {
264+ let dt = parse_time_to_datetime ( "2024-01-01T00:00:00Z" ) . unwrap ( ) ;
265+ assert_eq ! ( dt. timestamp_millis( ) , 1704067200000 ) ;
266+ }
267+
268+ #[ test]
269+ fn test_parse_time_to_datetime_invalid_input ( ) {
270+ let err = parse_time_to_datetime ( "not-a-time" ) . unwrap_err ( ) ;
271+ assert ! ( err. to_string( ) . contains( "unable to parse time" ) ) ;
272+ }
273+
274+ #[ test]
275+ fn test_parse_time_to_datetime_empty ( ) {
276+ assert ! ( parse_time_to_datetime( "" ) . is_err( ) ) ;
277+ }
278+
232279 #[ test]
233280 fn test_parse_time_to_unix_returns_seconds ( ) {
234281 let secs = parse_time_to_unix ( "1700000000000" ) . unwrap ( ) ;
0 commit comments