std::time em Rust: Duration, Instant e SystemTime

Guia completo do módulo std::time em Rust: Duration, Instant e SystemTime para medir tempo de execução, benchmarking e timestamps com exemplos.

Visao Geral do Modulo std::time

O modulo std::time fornece os tipos fundamentais para trabalhar com tempo em Rust. Diferente de muitas linguagens que misturam tempo absoluto e duracoes, Rust separa esses conceitos em tres tipos distintos:

  • Duration — representa um intervalo de tempo (sempre positivo)
  • Instant — um ponto no tempo monotonicamente crescente, ideal para medir duracao de operacoes
  • SystemTime — o relogio do sistema, que pode ser ajustado e pode retroceder

Essa separacao intencional evita bugs comuns como usar timestamps do sistema para medir performance (que falha quando o relogio e ajustado). O modulo faz parte da biblioteca padrao e nao requer crates externas para operacoes basicas de tempo.


Tipos e Funcoes Principais

Duration

Duration representa um intervalo de tempo com precisao de nanossegundos. E sempre nao-negativo e imutavel.

MetodoDescricao
Duration::from_secs(u64)Cria Duration a partir de segundos
Duration::from_millis(u64)Cria Duration a partir de milissegundos
Duration::from_micros(u64)Cria Duration a partir de microssegundos
Duration::from_nanos(u64)Cria Duration a partir de nanossegundos
Duration::from_secs_f64(f64)Cria Duration a partir de um float de segundos
Duration::ZERODuration de zero
.as_secs()Retorna apenas a parte inteira em segundos
.as_millis()Retorna duracao total em milissegundos
.as_micros()Retorna duracao total em microssegundos
.as_nanos()Retorna duracao total em nanossegundos
.as_secs_f64()Retorna como float de segundos
.subsec_millis()Retorna a parte fracionaria em milissegundos
.checked_add(Duration)Adicao segura (retorna Option)
.saturating_mul(u32)Multiplicacao com saturacao

Instant

Instant usa um relogio monotonico do sistema operacional. Ele nunca retrocede e e ideal para medir duracoes.

MetodoDescricao
Instant::now()Captura o instante atual
.elapsed()Duracao desde este instante ate agora
.duration_since(Instant)Duracao entre dois instantes
.checked_duration_since(Instant)Versao segura (retorna Option)
.checked_add(Duration)Adiciona duracao ao instante
.checked_sub(Duration)Subtrai duracao do instante

SystemTime

SystemTime representa o relogio do sistema (wall clock). Pode ser ajustado pelo usuario ou NTP, podendo retroceder.

MetodoDescricao
SystemTime::now()Hora atual do sistema
SystemTime::UNIX_EPOCH1 de janeiro de 1970, 00:00:00 UTC
.duration_since(SystemTime)Duracao entre dois pontos (pode falhar)
.elapsed()Duracao desde este ponto ate agora

Exemplos Praticos

1. Medindo Tempo de Execucao com Instant

O uso mais comum de std::time e medir quanto tempo uma operacao leva. Instant e a escolha certa porque usa um relogio monotonico:

use std::time::Instant;

fn operacao_custosa() -> u64 {
    (0..1_000_000u64).sum()
}

fn main() {
    let inicio = Instant::now();

    let resultado = operacao_custosa();

    let duracao = inicio.elapsed();

    println!("Resultado: {resultado}");
    println!("Tempo decorrido: {:.2?}", duracao);
    println!("Em milissegundos: {:.3}ms", duracao.as_secs_f64() * 1000.0);
}

2. Comparando Performance de Algoritmos

use std::time::Instant;

fn busca_linear(dados: &[i32], alvo: i32) -> Option<usize> {
    dados.iter().position(|&x| x == alvo)
}

fn busca_binaria(dados: &[i32], alvo: i32) -> Option<usize> {
    dados.binary_search(&alvo).ok()
}

fn medir<F, R>(nome: &str, iteracoes: u32, mut func: F)
where
    F: FnMut() -> R,
{
    let inicio = Instant::now();
    for _ in 0..iteracoes {
        std::hint::black_box(func());
    }
    let total = inicio.elapsed();
    let media = total / iteracoes;
    println!("{nome}: total={total:.2?}, media={media:.2?}");
}

fn main() {
    let dados: Vec<i32> = (0..10_000).collect();
    let alvo = 9_999;
    let iteracoes = 1_000;

    medir("Busca linear ", iteracoes, || busca_linear(&dados, alvo));
    medir("Busca binaria", iteracoes, || busca_binaria(&dados, alvo));
}

3. Trabalhando com SystemTime e UNIX_EPOCH

use std::time::{SystemTime, UNIX_EPOCH, Duration};

fn main() {
    // Timestamp atual em segundos desde UNIX_EPOCH
    let agora = SystemTime::now();
    let timestamp = agora
        .duration_since(UNIX_EPOCH)
        .expect("O relogio do sistema esta antes de 1970!")
        .as_secs();

    println!("Timestamp Unix atual: {timestamp}");

    // Convertendo um timestamp de volta para SystemTime
    let data_especifica = UNIX_EPOCH + Duration::from_secs(1_700_000_000);
    match data_especifica.elapsed() {
        Ok(duracao) => println!("Essa data foi ha {:.1} dias", duracao.as_secs_f64() / 86400.0),
        Err(e) => println!("Essa data esta no futuro por {:.1} dias",
                           e.duration().as_secs_f64() / 86400.0),
    }

    // SystemTime pode falhar (o relogio pode retroceder)
    let t1 = SystemTime::now();
    let t2 = SystemTime::now();
    match t2.duration_since(t1) {
        Ok(d) => println!("Diferenca: {d:?}"),
        Err(e) => println!("O relogio retrocedeu! Erro: {e:?}"),
    }
}

4. Criando e Manipulando Duracoes

use std::time::Duration;

fn formatar_duracao(d: Duration) -> String {
    let total_secs = d.as_secs();
    let horas = total_secs / 3600;
    let minutos = (total_secs % 3600) / 60;
    let segundos = total_secs % 60;
    let millis = d.subsec_millis();

    if horas > 0 {
        format!("{horas}h {minutos}m {segundos}s")
    } else if minutos > 0 {
        format!("{minutos}m {segundos}s")
    } else {
        format!("{segundos}.{millis:03}s")
    }
}

fn main() {
    // Diferentes formas de criar Duration
    let d1 = Duration::from_secs(3661); // 1h 1m 1s
    let d2 = Duration::from_millis(1500);
    let d3 = Duration::from_secs_f64(0.5);

    println!("{}", formatar_duracao(d1)); // 1h 1m 1s
    println!("{}", formatar_duracao(d2)); // 1.500s
    println!("{}", formatar_duracao(d3)); // 0.500s

    // Operacoes aritmeticas
    let soma = d2 + d3;
    println!("Soma: {soma:?}"); // 2s

    // Multiplicacao
    let triplicado = d3 * 3;
    println!("Triplicado: {triplicado:?}"); // 1.5s

    // Comparacao
    assert!(d1 > d2);
    assert_eq!(d2 + d3, Duration::from_secs(2));
}

5. Timeout Simples com Instant

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

fn processar_com_timeout<F>(timeout: Duration, mut trabalho: F) -> Result<(), String>
where
    F: FnMut() -> bool,
{
    let inicio = Instant::now();

    loop {
        if trabalho() {
            return Ok(());
        }

        if inicio.elapsed() > timeout {
            return Err(format!(
                "Timeout apos {:.2}s",
                timeout.as_secs_f64()
            ));
        }
    }
}

fn main() {
    let mut contador = 0u64;

    let resultado = processar_com_timeout(
        Duration::from_millis(100),
        || {
            contador += 1;
            contador >= 1_000_000
        },
    );

    match resultado {
        Ok(()) => println!("Concluido apos {contador} iteracoes"),
        Err(msg) => println!("{msg} (parcial: {contador} iteracoes)"),
    }
}

Padroes Comuns

Medindo Secoes de Codigo

O padrao mais frequente e envolver uma operacao entre Instant::now() e .elapsed():

use std::time::Instant;

fn main() {
    let t = Instant::now();
    // ... operacao ...
    eprintln!("[benchmark] operacao levou {:?}", t.elapsed());
}

Gerando Timestamps para Logs

Para logs e registros, use SystemTime com UNIX_EPOCH:

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

fn timestamp_millis() -> u128 {
    SystemTime::now()
        .duration_since(UNIX_EPOCH)
        .unwrap()
        .as_millis()
}

Aritmetica com Duration

Duration suporta soma, subtracao, multiplicacao e divisao. Versoes checked_* e saturating_* evitam panic em overflow:

use std::time::Duration;

fn main() {
    let base = Duration::from_secs(1);
    let dobro = base.saturating_mul(2);
    let soma = base.checked_add(Duration::from_millis(500));
    println!("{dobro:?}, {soma:?}");
}

Quando Usar (e Quando Nao Usar)

Use std::time quando:

  • Precisar medir tempo de execucao de operacoes
  • Precisar de timestamps Unix simples
  • Quiser implementar timeouts basicos
  • Precisar comparar performance entre abordagens

Nao use std::time quando:

  • Precisar de datas formatadas (dia, mes, ano) — use a crate chrono ou time
  • Precisar de fusos horarios — use crates externas
  • Precisar de benchmarks estatisticamente rigorosos — use criterion
  • Precisar de temporizadores assincronos — use tokio::time

Dica de performance: Instant::now() e extremamente rapido na maioria dos sistemas operacionais (usa clock_gettime no Linux com CLOCK_MONOTONIC). Nao hesite em usa-lo mesmo em hot paths.

Atencao com SystemTime: O resultado de duration_since pode ser um Err se o relogio do sistema foi ajustado para tras. Sempre trate esse caso, especialmente em codigo de producao.


Veja Tambem