Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Duration and Calculation

Measure the elapsed time between two code sections

std Date and time

Measures time::Instant::elapsed since time::Instant::now.

Calling time::Instant::elapsed returns a time::Duration that we print at the end of the recipe. This method will not mutate or reset the time::Instant object.

use std::time::{Duration, Instant};
use std::thread;

fn expensive_function() {
    thread::sleep(Duration::from_secs(1));
}

fn main() {
    let start = Instant::now();
    expensive_function();
    let duration = start.elapsed();

    println!("Time elapsed in expensive_function() is: {:?}", duration);
}

Deadline arithmetic with Instant

std Date and time

Calculates a one second Duration. Computes deadline one second from Instant::now. Sleeps for one second and compares deadline with Instant::now to check if the deadline has passed.

use std::thread;
use std::time::{Duration, Instant};
fn sleep(duration: Duration) {
   thread::sleep(duration);
}

fn main() {
    let one_second = Duration::from_secs(1);
    let deadline = Instant::now() + one_second;

    sleep(Duration::from_secs(1));
    if Instant::now() > deadline {
        println!("Deadline has passed");
    }
}

Convert SystemTime to Unix timestamp

std Date and time

Converts the current SystemTime to seconds since the Unix epoch, then computes the original time by adding the unix timestamp to SystemTime::UNIX_EPOCH constant.

use std::time::{SystemTime, SystemTimeError};

fn main() -> Result<(), SystemTimeError> {
    let now = SystemTime::now();
    let since_unix_epoch = now.duration_since(SystemTime::UNIX_EPOCH)?;
    println!("Unix timestamp: {}", since_unix_epoch.as_secs());

    let from_unix_timestamp = SystemTime::UNIX_EPOCH + since_unix_epoch;
    println!("Back to SystemTime: {:?}", from_unix_timestamp);

    Ok(())
}

Benchmark a closure with Instant

std Date and time

Initializes a weights vector, calculates half of its total sum into half_load, and uses benchmark to measure the performance of subset_sum which takes a slice of weights and a target value and finds a subset whose weights sum to the target.

benchmark measures the average time required to call a closure a specified number of times using Instant::now and Instant::elapsed. It uses black_box to prevent the compiler from optimizing away the closure’s computation since its return value is ignored.

use std::time::{Duration, Instant};

fn subset_sum(weights: &[u64], target: u64) -> Option<u32> {
    for mask in 0..1u32 << weights.len() {
        let sum: u64 = weights
            .iter()
            .enumerate()
            .filter(|(i, _)| mask >> i & 1 == 1)
            .map(|(_, weight)| weight)
            .sum();

        if sum == target {
            return Some(mask);
        }
    }
    None
}

fn benchmark<F, T>(runs: u32, mut f: F) -> Duration
where
    F: FnMut() -> T,
{
    let start = Instant::now();

    for _ in 0..runs {
        std::hint::black_box(f());
    }

    start.elapsed() / runs
}

fn main() {
    let weights: Vec<u64> = (1..=18).map(|kg| kg * 2).collect();
    let half_load = weights.iter().sum::<u64>() / 2;

    for parcels in 12..=weights.len() {
        let mean = benchmark(3, || subset_sum(&weights[..parcels], half_load));
        println!("{:2} parcels: {:>10.2?}", parcels, mean);
    }
}

Choosing between chrono, time and jiff

  • chrono and time are both very widely used, and both are supported by crates such as serde, diesel and sqlx. chrono has a larger API, but needs the separate chrono-tz crate for IANA time zones. time is smaller and only knows fixed UTC offsets, with no time zone database.
  • jiff has IANA time zone support built in, using the system’s time zone database, or a bundled copy on platforms without one. Its Span and Zoned types make DST-aware arithmetic the default. It has fewer third-party integrations so far.
  • All three are pre-1.0, so their APIs may still change.

If your code works with time zones and has no existing chrono or time dependency, jiff is worth considering. Otherwise stay with whatever your dependencies already use.

Perform checked date and time calculations

chrono Date and time

Calculates and displays the date and time two weeks from now using DateTime::checked_add_signed and the date of the day before that using DateTime::checked_sub_signed. The methods return None if the date and time cannot be calculated.

Escape sequences that are available for the DateTime::format can be found at chrono::format::strftime.

use chrono::{DateTime, Duration, Utc};

fn day_earlier(date_time: DateTime<Utc>) -> Option<DateTime<Utc>> {
    date_time.checked_sub_signed(Duration::days(1))
}

fn main() {
    let now = Utc::now();
    println!("{}", now);

    let almost_three_weeks_from_now = now
        .checked_add_signed(Duration::weeks(2))
        .and_then(|in_2weeks| in_2weeks.checked_add_signed(Duration::weeks(1)))
        .and_then(day_earlier);

    match almost_three_weeks_from_now {
        Some(x) => println!("{}", x),
        None => eprintln!("Almost three weeks from now overflows!"),
    }

    match now.checked_add_signed(Duration::max_value()) {
        Some(x) => println!("{}", x),
        None => eprintln!(
            "We can't use chrono to tell the time for the Solar System to complete more than one full orbit around the galactic center."
        ),
    }
}

Convert a local time to another timezone

chrono Date and time

Gets the local time and displays it using offset::Local::now and then converts it to the UTC standard using the DateTime::from_utc struct method. A time is then converted using the offset::FixedOffset struct and the UTC time is then converted to UTC+8 and UTC-2.

use chrono::{DateTime, FixedOffset, Local, Utc};

fn main() {
    let local_time = Local::now();
    let utc_time = DateTime::<Utc>::from_utc(local_time.naive_utc(), Utc);
    let china_timezone = FixedOffset::east(8 * 3600);
    let rio_timezone = FixedOffset::west(2 * 3600);
    println!("Local time now is {}", local_time);
    println!("UTC time now is {}", utc_time);
    println!(
        "Time in Hong Kong now is {}",
        utc_time.with_timezone(&china_timezone)
    );
    println!(
        "Time in Rio de Janeiro now is {}",
        utc_time.with_timezone(&rio_timezone)
    );
}