Tempo e data (time.h)
Esta aula explora a biblioteca time.h da linguagem C, cobrindo funções para obter tempo, formatar datas, medir desempenho e aplicar esses conceitos em exemplos práticos. O aluno aprenderá a usar time(), clock(), difftime(), strftime() e outras funções essenciais para manipulação de tempo.
A manipulação de tempo e data é uma necessidade comum em programas: registrar eventos, medir intervalos, exibir timestamps ou otimizar desempenho. A biblioteca padrão time.h fornece funções e tipos para lidar com tempo de forma portátil. Nesta aula, vamos explorar as principais funcionalidades dessa biblioteca, desde a obtenção do tempo atual até a formatação de datas e a medição precisa de desempenho.
Dominar essas funções é essencial para qualquer programador C que precise trabalhar com cronometragem, logs, agendamentos ou benchmarks. Veremos como converter entre representações de tempo, como usar relógios de alta resolução e como evitar armadilhas comuns.
time e clock
A função time() retorna o tempo atual em segundos desde a época (1 de janeiro de 1970, 00:00:00 UTC). O valor é do tipo time_t, que geralmente é um inteiro longo. Para obter o tempo, basta passar um ponteiro para time_t ou NULL:
#include <stdio.h>
#include <time.h>
int main() {
time_t agora = time(NULL);
printf("Segundos desde a época: %ld\n", (long)agora);
return 0;
}Já clock() mede o tempo de CPU gasto pelo programa, em unidades de CLOCKS_PER_SEC. É útil para medir o desempenho de trechos de código, pois conta o tempo de processador, não o tempo de parede. Exemplo:
#include <stdio.h>
#include <time.h>
int main() {
clock_t inicio = clock();
// Simula trabalho pesado
for (long i = 0; i < 100000000; i++);
clock_t fim = clock();
double tempo = (double)(fim - inicio) / CLOCKS_PER_SEC;
printf("Tempo de CPU: %f segundos\n", tempo);
return 0;
}Note que clock() pode não ser preciso em sistemas com múltiplos núcleos, pois conta o tempo de CPU total. Para medir tempo de parede, use time() ou gettimeofday() (não padrão).
Formatação
Para formatar datas e horas, usamos struct tm, que representa o tempo decomposto em campos (ano, mês, dia, hora, etc.). A função localtime() converte time_t para struct tm no fuso local, e gmtime() para UTC. Depois, strftime() formata conforme especificadores:
#include <stdio.h>
#include <time.h>
int main() {
time_t agora = time(NULL);
struct tm *info = localtime(&agora);
char buffer[80];
strftime(buffer, sizeof(buffer), "%d/%m/%Y %H:%M:%S", info);
printf("Data e hora: %s\n", buffer);
return 0;
}Especificadores comuns: %d dia, %m mês, %Y ano, %H hora (24h), %M minuto, %S segundo, %A nome do dia, %B nome do mês. Também podemos usar asctime() para uma formatação fixa, mas strftime() é mais flexível.
Medindo desempenho
Para medir o tempo de execução de um trecho de código, além de clock(), podemos usar time() para intervalos longos e clock_gettime() (POSIX) para alta precisão. O padrão C11 oferece timespec_get() que preenche uma estrutura struct timespec com resolução de nanossegundos:
#include <stdio.h>
#include <time.h>
int main() {
struct timespec inicio, fim;
timespec_get(&inicio, TIME_UTC);
// Trabalho
for (long i = 0; i < 100000000; i++);
timespec_get(&fim, TIME_UTC);
double seg = (fim.tv_sec - inicio.tv_sec) + (fim.tv_nsec - inicio.tv_nsec) / 1e9;
printf("Tempo decorrido: %f s\n", seg);
return 0;
}Essa abordagem é preferível quando precisamos de precisão. difftime() também pode ser usada para comparar dois time_t, retornando a diferença em segundos.
Exemplos
Vamos consolidar com um programa que exibe a data atual em vários formatos e mede o tempo de uma operação:
#include <stdio.h>
#include <time.h>
int main() {
// Obtém e formata a data
time_t agora = time(NULL);
struct tm *tm = localtime(&agora);
char data[100];
strftime(data, sizeof(data), "%A, %d de %B de %Y - %H:%M:%S", tm);
printf("%s\n", data);
// Mede o tempo de uma soma
clock_t c_inicio = clock();
long soma = 0;
for (long i = 0; i < 100000000; i++) soma += i;
clock_t c_fim = clock();
double cpu = (double)(c_fim - c_inicio) / CLOCKS_PER_SEC;
struct timespec t_inicio, t_fim;
timespec_get(&t_inicio, TIME_UTC);
soma = 0;
for (long i = 0; i < 100000000; i++) soma += i;
timespec_get(&t_fim, TIME_UTC);
double decorrido = (t_fim.tv_sec - t_inicio.tv_sec) + (t_fim.tv_nsec - t_inicio.tv_nsec)/1e9;
printf("Soma: %ld\n", soma);
printf("Tempo de CPU: %.6f s\n", cpu);
printf("Tempo de parede: %.6f s\n", decorrido);
return 0;
}Boas práticas
Ao trabalhar com tempo, prefira strftime() para formatação localizada, evite asctime() por não ser thread-safe, e use clock_gettime() ou timespec_get() para medições precisas. Sempre verifique o retorno de funções que podem falhar, como strftime() (retorna 0 se o buffer for pequeno).
Referências
- cppreference - Date and time utilities
- man7 - time(3p)
- man7 - clock_gettime(3)
- cppreference - strftime
- POSIX - strftime
Exercícios
Escreva um programa que imprima o tempo atual em segundos desde a época e em formato legível (dd/mm/aaaa hh:mm:ss).
✓ Resposta:#include <stdio.h> #include <time.h> int main() { time_t t = time(NULL); printf("Época: %ld\n", (long)t); struct tm *tm = localtime(&t); char buf[64]; strftime(buf, sizeof(buf), "%d/%m/%Y %H:%M:%S", tm); printf("Data: %s\n", buf); return 0; }Use
clock()para medir o tempo de CPU de um loop que realiza 1 milhão de iterações vazias. Imprima o tempo em segundos.✓ Resposta:#include <stdio.h> #include <time.h> int main() { clock_t start = clock(); for (int i = 0; i < 1000000; i++); clock_t end = clock(); printf("Tempo de CPU: %f s\n", (double)(end - start) / CLOCKS_PER_SEC); return 0; }Implemente uma função que receba um
time_te retorne uma string formatada como "YYYY-MM-DD HH:MM:SS" (usegmtimepara UTC).✓ Resposta:#include <stdio.h> #include <time.h> void formatar(time_t t, char *buf, size_t tam) { struct tm *tm = gmtime(&t); strftime(buf, tam, "%Y-%m-%d %H:%M:%S", tm); } int main() { time_t agora = time(NULL); char buf[32]; formatar(agora, buf, sizeof(buf)); printf("%s\n", buf); return 0; }Compare o tempo de parede (usando
time()) com o tempo de CPU (usandoclock()) para uma operação que dorme 1 segundo (sleep(1)). Explique a diferença.✓ Resposta:#include <stdio.h> #include <time.h> #include <unistd.h> // para sleep int main() { time_t t1 = time(NULL); clock_t c1 = clock(); sleep(1); time_t t2 = time(NULL); clock_t c2 = clock(); printf("Tempo de parede: %ld s\n", (long)(t2 - t1)); printf("Tempo de CPU: %f s\n", (double)(c2 - c1) / CLOCKS_PER_SEC); return 0; }A diferença ocorre porque
sleep()não consome CPU; o processo fica bloqueado, então o tempo de CPU é próximo de zero, enquanto o tempo de parede é de 1 segundo.Use
timespec_get()para medir o tempo de uma função que calcula a soma de 1 a 1000000 e imprima o resultado com 9 casas decimais.✓ Resposta:#include <stdio.h> #include <time.h> int main() { struct timespec inicio, fim; timespec_get(&inicio, TIME_UTC); long soma = 0; for (long i = 1; i <= 1000000; i++) soma += i; timespec_get(&fim, TIME_UTC); double tempo = (fim.tv_sec - inicio.tv_sec) + (fim.tv_nsec - inicio.tv_nsec) / 1e9; printf("Soma: %ld\n", soma); printf("Tempo: %.9f s\n", tempo); return 0; }