@@ -5,6 +5,8 @@ use chrono::{DateTime, FixedOffset, Local, LocalResult, NaiveDateTime, TimeZone}
5
5
6
6
use crate :: ParseDurationError ;
7
7
8
+ use crate :: from_str as parse_relative_time;
9
+
8
10
/// Formats that parse input can take.
9
11
/// Taken from `touch` coreutils
10
12
mod format {
@@ -46,6 +48,8 @@ mod format {
46
48
///
47
49
/// * ISO formats
48
50
/// * timezone offsets, e.g., "UTC-0100"
51
+ /// * unix timestamps, e.g., "@12"
52
+ /// * relative time to now, e.g. "+1 hour"
49
53
///
50
54
/// # Returns
51
55
///
@@ -123,6 +127,15 @@ pub fn from_str<S: AsRef<str> + Clone>(s: S) -> Result<DateTime<FixedOffset>, Pa
123
127
}
124
128
}
125
129
130
+ // Parse relative time.
131
+ if let Ok ( relative_time) = parse_relative_time ( s. as_ref ( ) ) {
132
+ let current_time = DateTime :: < FixedOffset > :: from ( Local :: now ( ) ) ;
133
+
134
+ if let Some ( date_time) = current_time. checked_add_signed ( relative_time) {
135
+ return Ok ( date_time) ;
136
+ }
137
+ }
138
+
126
139
// Default parse and failure
127
140
s. as_ref ( )
128
141
. parse ( )
@@ -243,6 +256,46 @@ mod tests {
243
256
}
244
257
}
245
258
259
+ #[ cfg( test) ]
260
+ mod relative_time {
261
+ use chrono:: Local ;
262
+
263
+ use crate :: { parse_datetime:: from_str, ParseDurationError } ;
264
+
265
+ #[ test]
266
+ fn test_positive_offsets ( ) {
267
+ let relative_times = vec ! [
268
+ "today" ,
269
+ "yesterday" ,
270
+ "1 minute" ,
271
+ "3 hours" ,
272
+ "1 year 3 months" ,
273
+ ] ;
274
+
275
+ for relative_time in relative_times {
276
+ assert_eq ! ( from_str( relative_time) . is_ok( ) , true ) ;
277
+ }
278
+ }
279
+
280
+ #[ test]
281
+ fn test_partial_offset ( ) {
282
+ let offsets = vec ! [ "UTC+00:15" , "UTC+0015" , "Z+00:15" , "Z+0015" ] ;
283
+ let expected = format ! ( "{}{}" , Local :: now( ) . format( "%Y%m%d" ) , "0000+0015" ) ;
284
+ for offset in offsets {
285
+ let actual = from_str ( offset) . unwrap ( ) ;
286
+ assert_eq ! ( expected, format!( "{}" , actual. format( "%Y%m%d%H%M%z" ) ) ) ;
287
+ }
288
+ }
289
+
290
+ #[ test]
291
+ fn invalid_offset_format ( ) {
292
+ let invalid_offsets = vec ! [ "+0700" , "UTC+2" , "Z-1" , "UTC+01005" ] ;
293
+ for offset in invalid_offsets {
294
+ assert_eq ! ( from_str( offset) , Err ( ParseDurationError :: InvalidInput ) ) ;
295
+ }
296
+ }
297
+ }
298
+
246
299
/// Used to test example code presented in the README.
247
300
mod readme_test {
248
301
use crate :: parse_datetime:: from_str;
0 commit comments