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.
- 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 literais500ms,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_clocke formatá-las comstd::formatC++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:
| Ideia | No dia a dia | Em C++ |
|---|---|---|
| Duração | "90 segundos", "meia hora" | std::chrono::seconds, minutes… |
| Relógio | O 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, escrever500msé 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
doubleguarda frações, eratio<60>quer dizer "cada unidade vale 60 segundos". É raro precisar disso; fica para você reconhecer.
| Tipo | Literal | Unidade |
|---|---|---|
std::chrono::nanoseconds | 10ns | bilionésimo de segundo |
std::chrono::microseconds | 10us | milionésimo de segundo |
std::chrono::milliseconds | 10ms | milésimo de segundo |
std::chrono::seconds | 10s | segundo |
std::chrono::minutes | 10min | minuto |
std::chrono::hours | 10h | hora |
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
%Smostraria 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.
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
coutmostra no formato internacionalAAAA-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… | Use | Por quê |
|---|---|---|
| Medir quanto tempo algo levou | steady_clock | Nunca anda para trás, mesmo se a hora do sistema for ajustada. |
| Saber a data e a hora | system_clock (+ zoned_time para a hora local) | É o relógio do calendário. |
| Esperar | std::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.
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 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
| Escrita | O 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 - inicio | Duraçã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 << d | Mostra 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 / 16 | Uma 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:
2. Meio segundo
Complete com o literal de meio segundo em milissegundos:
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 comduration_cast. Os tempos variam a cada execução: meça mais de uma vez. - Literais (
500ms,2s,1h) exigemusing 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_clockestá em UTC; para a hora local,zoned_timecomcurrent_zone(). Formate comstd::format("{:%d/%m/%Y}", …).- Datas do calendário:
2026y / December / 25, e subtrairsys_daysdá dias.