tokio icon indicating copy to clipboard operation
tokio copied to clipboard

Expose a new `tokio::time::SystemTime` API

Open LucioFranco opened this issue 4 years ago • 2 comments

Problem

There is no way to currently get the time since epoch from tokio::time::Instant. For test case that require this functionality they can't take advantage of the time::pause/time::advance API that exists within Tokio. They instead must roll their own clock API using thread locals which is error prone and cumbersome.

Proposal

Add a SystemTime API to tokio::time similar to that of tokio::time::Instant. The idea is to support the same test utils that we have for Instant within Tokio. The idea here is to not provide a comprehensive way to test system time usage but to provide a simple API to expose the more fine grained details around a complex time API that is not possible with the current Instant API (for good reason). This API would follow what we do for Instant within time/clock.rs except also keep track of a SystemTime type along side the Instant.

Calling time::pause would pause both the Instant::now and SystemTime::now API. When compiled without test-utils it would just call the std version but with test-utils enabled now would defer to the built in tokio clock. This then allows time::pause and time::advance work.

The benefit to having a SystemTime API is similar to that of Instant. They provide an easy way to have a mockable clock within a #[tokio::test] situation. This is because the Clock within tokio is always implicitly set when the time feature is enabled. This means all futures spawned onto that runtime would share the same mocked clock. This provides a clear way to execute code within the mocked context as that context is the same as the tokio runtime context. This then allows users to use a single mock clock for all their testing needs.

Proposed API

pub struct SystemTime { ... }

impl SystemTime {
    pub fn now() -> Self {
        #[cfg(feature = "test-utils"]
        // Get the mocked time from the built-in tokio clock.
        clock::system_now()

        #[cfg(not(feature = "test-utils"))]
        // Get the time from the system API
        std::time::SystemTime::now().into()
    }

    // Follows the rest of the API in https://doc.rust-lang.org/stable/std/time/struct.SystemTime.html
}

Advanced features

In this iteration we would not provide any advanced testing functionality like inducing a clock that skews backwards. The idea here is to provide a trivial SystemTime API that can pause/advance time. It should also be simple to use and get started with. It should come bundled in the runtime if time is enabled and can be tested using the test-utils. Beyond that all other fault injection style features would be punted and implemented in tokio-simulation.

LucioFranco avatar Dec 15 '20 20:12 LucioFranco

Lucio mentioned on Discord that he makes extensive use of Tokio's test-util timer features. They use std::time::SystemTime in tandem with UNIX_EPOCH to get measures of the "elapsed time" in tests. Unfortunately, since Tokio's timer mocks don't integrate with the std's system time, they've created their own fake clocks, but they think portions of this could live in Tokio for integration purposes and removing the need to have their own mocked clocks.

davidbarsky avatar Dec 15 '20 20:12 davidbarsky

I'm bringing this issue up again: I'd be interested to know if there have been any developments in this regard since then?

I have a similar need :

They use std::time::SystemTime in tandem with UNIX_EPOCH to get measures of the "elapsed time"

Thanks !

mablr avatar Jun 05 '25 09:06 mablr