C++ Tempo e Datas (chrono)

Quanto tempo o programa da Ana leva para ordenar a lista? Como esperar meio segundo antes de mostrar o próximo número da contagem regressiva? Que dia é hoje, e quantos dias faltam para o Natal? Tudo isso mora no cabeçalho <chrono> (de chronos, "tempo" em grego). Ele é famoso por ter nomes compridos, mas a ideia é simples e segura: o C++ sabe a unidade de cada tempo (segundos, milissegundos, minutos) e não deixa você misturar sem querer.

Você vai aprender
  • Medir quanto tempo um trecho de código leva, com std::chrono::steady_clock.
  • Trabalhar com durações: std::chrono::seconds, milliseconds, minutes, e os literais 500ms, 2s, 1h.
  • Converter entre unidades com duration_cast, e por que algumas conversões não compilam.
  • Pausar o programa com std::this_thread::sleep_for.
  • Pegar a data e a hora atuais com system_clock e formatá-las com std::format C++20.
  • Usar o fuso horário (current_zone) e fazer contas com datas.

Os programas foram compilados com o g++ 15.2 na máquina fictícia da Ana, na pasta ~/cpp, com g++ -std=c++23 -Wall -Wextra arquivo.cpp -o programa. Atenção: nesta aula, várias saídas dependem do relógio. Os tempos medidos mudam a cada execução e de computador para computador, e as datas mostram o dia em que rodamos os exemplos (16 de outubro de 2026, à noite). No seu computador, os números serão outros.


A ideia: o cronômetro e o relógio de parede

O <chrono> separa três ideias que, no dia a dia, a gente mistura:

IdeiaNo dia a diaEm C++
Duração"90 segundos", "meia hora"std::chrono::seconds, minutes…
RelógioO cronômetro (só mede intervalos) e o relógio de parede (diz que horas são)steady_clock e system_clock
Instante"agora", "quando apertei o botão"um time_point, o que now() devolve

A conta que liga as três é a mesma do cronômetro: instante final − instante inicial = duração.

Todos os nomes ficam dentro de std::chrono. Para não escrever isso toda hora, alguns exemplos usam using namespace std::chrono; dentro do main (aula Namespaces), o que vale só ali dentro.


1. Medir quanto tempo um trecho leva

#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <vector>

int main() {
    std::vector<int> numeros(1'000'000);
    std::mt19937 gerador(42);
    for (int& n : numeros) {
        n = static_cast<int>(gerador() % 1000);
    }

    auto inicio = std::chrono::steady_clock::now();
    std::sort(numeros.begin(), numeros.end());
    auto fim = std::chrono::steady_clock::now();

    auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(fim - inicio);
    std::cout << "Ordenar 1 milhão de números levou " << ms.count() << " ms\n";
}
$ g++ -std=c++23 -Wall -Wextra medir.cpp -o medir
$ ./medir
Ordenar 1 milhão de números levou 240 ms
$ ./medir
Ordenar 1 milhão de números levou 234 ms
$ ./medir
Ordenar 1 milhão de números levou 243 ms       « o mesmo programa, três tempos diferentes
std::chrono::steady_clock::now()
"Que instante é agora, no cronômetro?" Steady = "firme", "constante": esse relógio só anda para a frente, no mesmo ritmo, mesmo se alguém mudar a hora do computador. É o certo para medir.
fim - inicio
Subtrair dois instantes dá uma duração, na unidade mais fina do relógio (no Linux, nanossegundos).
duration_cast<std::chrono::milliseconds>(…)
Converte a duração para milissegundos (milésimos de segundo), jogando fora o que sobra. Cast = "conversão forçada".
ms.count()
O número "puro" dentro da duração, para mostrar.

Por que os tempos variam? Porque o computador está fazendo outras coisas ao mesmo tempo (o sistema, o navegador, outros programas), e a memória e o processador nem sempre estão no mesmo estado. Por isso, ao comparar dois jeitos de fazer algo, meça várias vezes. E compile com otimização (-O2) para medir de verdade: o comando padrão do guia, sem -O2, deixa o programa bem mais lento (aula Compilar com g++). O 1'000'000 com apóstrofos é só um jeito legível de escrever um milhão (aula Inteiros); o std::mt19937 gera os números sorteados (aula Números Aleatórios).

Experimente: rode duas ou três vezes e compare os tempos (no navegador eles serão diferentes dos do laboratório, e mudam a cada vez). Depois troque 10'000'000 por 1'000'000: o tempo cai mais ou menos dez vezes?

#include <chrono>
#include <iostream>

int main() {
    auto inicio = std::chrono::steady_clock::now();

    long long soma = 0;
    for (int i = 1; i <= 10'000'000; ++i) {
        soma += i % 7;
    }

    auto fim = std::chrono::steady_clock::now();
    auto us = std::chrono::duration_cast<std::chrono::microseconds>(fim - inicio);
    std::cout << "Soma: " << soma << '\n';
    std::cout << "Levou " << us.count() << " microssegundos\n";
}

No laboratório, duas execuções deste mesmo programa:

$ ./tempo_editor
Soma: 29999997
Levou 36121 microssegundos
$ ./tempo_editor
Soma: 29999997
Levou 38334 microssegundos

2. Durações e suas unidades

Uma duração é "um número + uma unidade". O tipo carrega a unidade, então o C++ faz as contas certas sozinho:

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono_literals;

    std::chrono::seconds intervalo = 90s;
    std::chrono::milliseconds espera = 500ms;
    std::chrono::minutes aula = 50min;

    std::cout << "Intervalo: " << intervalo.count() << " segundos\n";
    std::cout << "Espera: " << espera.count() << " milissegundos\n";
    std::cout << "Aula: " << aula << '\n';

    std::chrono::milliseconds total = intervalo + espera;
    std::cout << "Total: " << total << '\n';

    auto em_minutos = std::chrono::duration_cast<std::chrono::minutes>(intervalo);
    std::cout << "90s em minutos inteiros: " << em_minutos << '\n';

    std::chrono::duration<double, std::ratio<60>> exato = intervalo;
    std::cout << "90s em minutos com vírgula: " << exato.count() << '\n';

    std::cout << std::boolalpha << "1h == 60min? " << (1h == 60min) << '\n';
}
$ g++ -std=c++23 -Wall -Wextra duracoes.cpp -o duracoes
$ ./duracoes
Intervalo: 90 segundos
Espera: 500 milissegundos
Aula: 50min                          « desde o C++20, o cout mostra a unidade sozinho
Total: 90500ms                       « 90 s + 500 ms, convertido para ms
90s em minutos inteiros: 1min        « o duration_cast corta: 1,5 vira 1
90s em minutos com vírgula: 1.5
1h == 60min? true
using namespace std::chrono_literals;
Libera os literais de tempo: 90s, 500ms, 50min, 1h. Sem essa linha, escrever 500ms é erro.
std::chrono::seconds intervalo = 90s;
Uma duração em segundos. O mesmo valor também poderia ser escrito std::chrono::seconds{90}.
intervalo + espera
Segundos + milissegundos: o C++ converte tudo para a unidade mais fina (ms) antes de somar. Nada se perde.
duration_cast<std::chrono::minutes>(intervalo)
Converter para uma unidade maior pode perder informação (90 s não é um número inteiro de minutos). Por isso é preciso pedir com duration_cast, que corta a parte quebrada.
duration<double, std::ratio<60>>
Uma duração "em minutos com vírgula": o double guarda frações, e ratio<60> quer dizer "cada unidade vale 60 segundos". É raro precisar disso; fica para você reconhecer.
TipoLiteralUnidade
std::chrono::nanoseconds10nsbilionésimo de segundo
std::chrono::microseconds10usmilionésimo de segundo
std::chrono::milliseconds10msmilésimo de segundo
std::chrono::seconds10ssegundo
std::chrono::minutes10minminuto
std::chrono::hours10hhora
std::chrono::days, weeks, months, years(sem literal de duração)C++20; usados com datas

A conversão que perde informação não acontece sozinha

Ir de unidade grande para pequena (segundos → milissegundos) é sempre exato, e o C++ faz sem pedir. Ir de pequena para grande, não:

$ cat perda.cpp
#include <chrono>

int main() {
    using namespace std::chrono_literals;
    std::chrono::milliseconds espera = 1500ms;
    std::chrono::seconds s = espera;
    return static_cast<int>(s.count());
}
$ g++ -std=c++23 -Wall -Wextra perda.cpp -o perda
perda.cpp: In function ‘int main()’:
perda.cpp:6:30: error: conversion from ‘duration<[...],ratio<[...],1000>>’ to non-scalar type ‘duration<[...],ratio<[...],1>>’ requested
    6 |     std::chrono::seconds s = espera;
      |                              ^~~~~~

A mensagem é enigmática, mas dá para decifrar: ratio<[...],1000> é "1/1000 de segundo" (milissegundo) e ratio<[...],1> é "1/1 de segundo" (segundo); o [...] são partes iguais nos dois tipos que o g++ escondeu. Ou seja: "não converto milissegundos em segundos assim". 1500 ms não é um número inteiro de segundos, e o C++ se recusa a jogar fora meio segundo em silêncio. Se cortar é o que você quer, diga: std::chrono::duration_cast<std::chrono::seconds>(espera) (dá 1 s). Compare com a armadilha do accumulate da aula Algoritmos, que corta sem avisar: aqui o tipo protege você.


3. Pausar: std::this_thread::sleep_for

Para o programa "dormir" por um tempo, use sleep_for ("dormir por"), do cabeçalho <thread>, com uma duração:

#include <chrono>
#include <iostream>
#include <thread>

int main() {
    using namespace std::chrono_literals;

    for (int i = 3; i >= 1; --i) {
        std::cout << i << "...\n";
        std::this_thread::sleep_for(500ms);
    }
    std::cout << "Já!\n";
}
$ g++ -std=c++23 -Wall -Wextra dormir.cpp -o dormir
$ time ./dormir
3...
2...
1...
Já!

real	0m1,503s                        « 3 × 0,5 s = 1,5 s (e uns milissegundos a mais)
user	0m0,001s                        « dormindo, o programa quase não usa o processador
sys	0m0,002s

O time, escrito antes do programa, é um recurso do bash que mede quanto tempo o programa inteiro levou. this_thread quer dizer "esta linha de execução", o próprio programa; o assunto "threads" tem aula própria, Threads. O sleep_for garante que dorme pelo menos o tempo pedido, nunca menos; pode dormir um pouco mais.


4. Data e hora de agora C++20

Para saber que horas são, o relógio certo é o system_clock, o "relógio de parede" do sistema. Desde o C++20, o std::format (aula std::format e std::print) sabe formatar datas com códigos como %d (dia), %m (mês), %Y (ano com 4 dígitos), %H (hora) e %M (minuto):

#include <chrono>
#include <format>
#include <iostream>

int main() {
    auto agora = std::chrono::system_clock::now();

    std::cout << std::format("Data (UTC): {:%d/%m/%Y}\n", agora);
    std::cout << std::format("Hora (UTC): {:%H:%M}\n", agora);

    auto fuso = std::chrono::current_zone();
    std::chrono::zoned_time local{fuso, std::chrono::floor<std::chrono::seconds>(agora)};
    std::cout << std::format("Data local: {:%d/%m/%Y}\n", local);
    std::cout << std::format("Hora local: {:%H:%M:%S %Z}\n", local);
}
$ g++ -std=c++23 -Wall -Wextra agora.cpp -o agora
$ ./agora
Data (UTC): 17/10/2026                         « já é dia 17 em Greenwich…
Hora (UTC): 01:03
Data local: 16/10/2026                         « …mas ainda é dia 16 no Brasil
Hora local: 22:03:40 -03
$ date
sex 16 out 2026 22:03:40 -03
std::chrono::system_clock::now()
O instante atual no relógio do sistema.
{:%d/%m/%Y}
Dentro das chaves do format, depois dos dois-pontos, vem o "molde" da data. As barras são texto comum.
std::chrono::current_zone()
O fuso horário configurado no computador.
std::chrono::zoned_time local{fuso, …}
"Este instante, visto neste fuso." É ele que dá a hora local.
std::chrono::floor<std::chrono::seconds>(agora)
Arredonda o instante para baixo, para segundos inteiros. Sem isso, o %S mostraria os segundos com nove casas decimais.
%Z
A abreviação do fuso. Aqui saiu -03: três horas a menos que Greenwich, o horário de Brasília.
O system_clock conta em UTC

O system_clock não sabe de fuso: ele mostra o horário UTC (o "horário universal", de Greenwich, em Londres). No Brasil (UTC−3), entre 21h e meia-noite, a data UTC já é o dia seguinte, como no exemplo, rodado às 22h do dia 16. Para mostrar ao usuário, use a hora local, com zoned_time e current_zone().

Sobre o fuso: o current_zone() funciona no g++ 15 do Linux porque ele lê o banco de fusos horários do sistema (o pacote tzdata do Ubuntu). No editor do guia, que roda dentro do navegador, não há esse banco; por isso a parte de fuso fica só no terminal.

Contas com datas

O C++20 também trouxe tipos de calendário. Com eles, "quantos dias faltam para o Natal?" vira uma subtração:

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;

    zoned_time agora{current_zone(), system_clock::now()};
    auto hoje = floor<days>(agora.get_local_time());
    year_month_day data{hoje};
    std::cout << "Hoje: " << data << '\n';

    auto natal = local_days{data.year() / December / 25};
    auto faltam = natal - hoje;
    std::cout << "Faltam " << faltam.count() << " dias para o Natal\n";
}
$ g++ -std=c++23 -Wall -Wextra natal.cpp -o natal
$ ./natal
Hoje: 2026-10-16
Faltam 70 dias para o Natal
agora.get_local_time()
O instante atual no horário local.
floor<days>(…)
Arredonda para baixo, para o dia inteiro (joga fora as horas).
year_month_day data{hoje};
Separa o dia em ano, mês e dia. O cout mostra no formato internacional AAAA-MM-DD.
data.year() / December / 25
Monta uma data: "deste ano, dezembro, dia 25". As barras aqui não são divisão: o <chrono> as usa para montar datas.
natal - hoje
Diferença entre dois dias: uma duração em days.

Se você usar a data do system_clock direto (floor<days>(system_clock::now())), cai na armadilha do UTC: no mesmo minuto, esse programa mostrou Hoje (UTC): 2026-10-17, um dia adiantado.


Qual relógio usar?

Para…UsePor quê
Medir quanto tempo algo levousteady_clockNunca anda para trás, mesmo se a hora do sistema for ajustada.
Saber a data e a horasystem_clock (+ zoned_time para a hora local)É o relógio do calendário.
Esperarstd::this_thread::sleep_for(duração)Recebe uma duração com unidade: sleep_for(500ms) não tem como ser confundido com 500 segundos.

Você ainda vai encontrar high_resolution_clock em exemplos pela internet. No g++ ele é só outro nome para o system_clock, que pode ser ajustado; para medir, prefira o steady_clock. Em código antigo do C, aparecem também time(), clock() e strftime; o <chrono> substitui todos eles com mais segurança.


Quando dá errado

error: conversion from ‘duration<[...],ratio<[...],1000>>’ to non-scalar type ‘duration<[...],ratio<[...],1>>’ requested

O que significa: você tentou guardar uma duração numa unidade maior (ms → s), o que poderia perder a parte quebrada.

Como consertar: se quer cortar, use duration_cast<std::chrono::seconds>(…); se não quer perder nada, guarde na unidade menor (milliseconds) ou numa duração com double.

A data sai um dia adiantada

O que significa: você formatou o system_clock::now() direto, e ele está em UTC. À noite no Brasil, em UTC já é o dia seguinte.

Como consertar: converta para a hora local com std::chrono::zoned_time{std::chrono::current_zone(), agora}.

O tempo medido sai 0

O que significa: o trecho foi mais rápido que a unidade escolhida (levou 300 microssegundos e você converteu para seconds ou milliseconds), ou, com -O2, o compilador percebeu que o resultado não era usado e apagou o trecho inteiro.

Como consertar: use uma unidade menor (microseconds, nanoseconds) e use o resultado do trecho (mostre-o na tela, como a soma do exemplo).

500ms não compila

O que significa: faltou liberar os literais.

Como consertar: using namespace std::chrono_literals; dentro da função (ou using namespace std::chrono;, que também os inclui).


Referência rápida

EscritaO que faz
std::chrono::steady_clock::now()Instante no cronômetro (para medir)
std::chrono::system_clock::now()Instante no relógio do sistema (UTC)
fim - inicioDuração entre dois instantes
std::chrono::duration_cast<std::chrono::milliseconds>(d)Converte cortando a parte quebrada
d.count()O número dentro da duração
std::cout << dMostra com a unidade (500ms), C++20
using namespace std::chrono_literals;Libera 2h, 30min, 10s, 500ms, 10us, 10ns
std::this_thread::sleep_for(500ms);Pausa pelo menos esse tempo (<thread>)
std::format("{:%d/%m/%Y %H:%M}", t)Formata data e hora (C++20, <format>)
std::chrono::current_zone()Fuso horário do computador
std::chrono::zoned_time{fuso, t}Instante visto num fuso (hora local)
2026y / October / 16Uma data (com using namespace std::chrono;)
sys_days{a} - sys_days{b}Dias entre duas datas

Exercícios

1. O relógio para medir

Complete com o relógio certo para medir quanto tempo um trecho leva:

auto inicio = std::chrono::::now();

2. Meio segundo

Complete com o literal de meio segundo em milissegundos:

std::this_thread::sleep_for();

3. O que mostra std::cout << std::chrono::duration_cast<std::chrono::minutes>(150s).count();?

4. std::chrono::seconds s = 2500ms; compila?

5. Por que a data do system_clock::now() pode sair com um dia a mais à noite no Brasil?

Missão: segundos em horas, minutos e segundos

Missão: o vídeo da aula da Ana tem 3725 segundos. Mostre a duração como 1h 2min 5s. Dica: duration_cast<hours> dá as horas inteiras; tire-as do total com -=; faça o mesmo com os minutos; o que sobra são os segundos. O cout já escreve a unidade de cada duração.

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    using namespace std::chrono_literals;

    seconds total = 3725s;

    // calcule h e m aqui

    std::cout << total << '\n';
}
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;
    using namespace std::chrono_literals;

    seconds total = 3725s;

    auto h = duration_cast<hours>(total);
    total -= h;
    auto m = duration_cast<minutes>(total);
    total -= m;

    std::cout << h << ' ' << m << ' ' << total << '\n';
}

Missão final: dias até o Natal, numa data fixa

Missão: sem depender do relógio (para dar sempre o mesmo resultado), calcule quantos dias há entre 16 de outubro de 2026 e 25 de dezembro de 2026. Crie duas variáveis sys_days com 2026y / October / 16 e 2026y / December / 25 e subtraia. A saída deve ser Do dia 2026-10-16 ao Natal: 70 dias.

#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;

    // crie inicio e natal aqui

    // mostre: Do dia 2026-10-16 ao Natal: 70 dias
}
#include <chrono>
#include <iostream>

int main() {
    using namespace std::chrono;

    sys_days inicio = 2026y / October / 16;
    sys_days natal = 2026y / December / 25;

    auto diferenca = natal - inicio;
    std::cout << "Do dia " << year_month_day{inicio} << " ao Natal: "
              << diferenca.count() << " dias\n";
}

A solução, no laboratório:

$ g++ -std=c++23 -Wall -Wextra dias.cpp -o dias
$ ./dias
Do dia 2026-10-16 ao Natal: 70 dias

Resumo

  • <chrono> separa durações (seconds, milliseconds…), relógios e instantes (now()).
  • Para medir: steady_clock::now() antes e depois, subtraia, converta com duration_cast. Os tempos variam a cada execução: meça mais de uma vez.
  • Literais (500ms, 2s, 1h) exigem using namespace std::chrono_literals;.
  • Unidade grande → pequena é automático; pequena → grande exige duration_cast (que corta).
  • std::this_thread::sleep_for(500ms) pausa o programa.
  • system_clock está em UTC; para a hora local, zoned_time com current_zone(). Formate com std::format("{:%d/%m/%Y}", …).
  • Datas do calendário: 2026y / December / 25, e subtrair sys_days dá dias.