@@ -58,10 +58,20 @@ impl Sub<Duration> for Eternity {
5858 }
5959}
6060
61+ #[ derive( Clone , Copy , Debug , PartialEq , Eq ) ]
62+ #[ cfg( not( feature = "no-std" ) ) ]
63+ pub struct MonotonicTime ( std:: time:: Instant ) ;
64+
65+ /// The amount of time to shift `Instant` forward to prevent overflow when subtracting a `Duration`
66+ /// from `Instant::now` on some operating systems (e.g., iOS representing `Instance` as `u64`).
67+ #[ cfg( not( feature = "no-std" ) ) ]
68+ const SHIFT : Duration = Duration :: from_secs ( 10 * 365 * 24 * 60 * 60 ) ; // 10 years.
69+
6170#[ cfg( not( feature = "no-std" ) ) ]
62- impl Time for std :: time :: Instant {
71+ impl Time for MonotonicTime {
6372 fn now ( ) -> Self {
64- std:: time:: Instant :: now ( )
73+ let instant = std:: time:: Instant :: now ( ) . checked_add ( SHIFT ) . expect ( "Overflow on MonotonicTime instantiation" ) ;
74+ Self ( instant)
6575 }
6676
6777 fn duration_since ( & self , earlier : Self ) -> Duration {
@@ -70,15 +80,26 @@ impl Time for std::time::Instant {
7080 // clocks" that go backwards in practice (likely relatively ancient kernels/etc). Thus, we
7181 // manually check for time going backwards here and return a duration of zero in that case.
7282 let now = Self :: now ( ) ;
73- if now > earlier { now - earlier } else { Duration :: from_secs ( 0 ) }
83+ if now. 0 > earlier. 0 { now. 0 - earlier. 0 } else { Duration :: from_secs ( 0 ) }
7484 }
7585
7686 fn duration_since_epoch ( ) -> Duration {
7787 use std:: time:: SystemTime ;
7888 SystemTime :: now ( ) . duration_since ( SystemTime :: UNIX_EPOCH ) . unwrap ( )
7989 }
90+
8091 fn elapsed ( & self ) -> Duration {
81- std:: time:: Instant :: elapsed ( self )
92+ Self :: now ( ) . 0 - self . 0
93+ }
94+ }
95+
96+ #[ cfg( not( feature = "no-std" ) ) ]
97+ impl Sub < Duration > for MonotonicTime {
98+ type Output = Self ;
99+
100+ fn sub ( self , other : Duration ) -> Self {
101+ let instant = self . 0 . checked_sub ( other) . expect ( "MonotonicTime is not supposed to go backward futher than 10 years" ) ;
102+ Self ( instant)
82103 }
83104}
84105
@@ -154,4 +175,15 @@ pub mod tests {
154175 assert_eq ! ( now. elapsed( ) , Duration :: from_secs( 0 ) ) ;
155176 assert_eq ! ( later - elapsed, now) ;
156177 }
178+
179+ #[ test]
180+ #[ cfg( not( feature = "no-std" ) ) ]
181+ fn monotonic_time_subtracts ( ) {
182+ let now = super :: MonotonicTime :: now ( ) ;
183+ assert ! ( now. elapsed( ) < Duration :: from_secs( 10 ) ) ;
184+
185+ let ten_years = Duration :: from_secs ( 10 * 365 * 24 * 60 * 60 ) ;
186+ let past = now - ten_years;
187+ assert ! ( past. elapsed( ) >= ten_years) ;
188+ }
157189}
0 commit comments