Introdução: Por que precisamos de "tempo relativo"?
\n\nVocê já se perguntou por que as redes sociais e sites de notícias escrevem "2 horas atrás" ou "ontem", em vez de "25.04.2025 14:32"? Porque nosso cérebro processa o tempo relativo muito mais rápido. Uma data absoluta exige análise: "Ok, hoje é dia 25, então isso foi...". Uma data relativa dá a resposta instantaneamente.
\n\nSe você programa em C# — seja uma aplicação web em ASP.NET, um aplicativo desktop ou um bot do Telegram — mais cedo ou mais tarde precisará mostrar ao usuário o tempo no formato "agora mesmo", "3 minutos atrás" ou "cerca de um ano atrás". No Stack Overflow, a pergunta "Calculate relative time in C#" acumulou milhares de visualizações, o que significa que é uma verdadeira dor de cabeça para os desenvolvedores.
\n\nNeste artigo, vamos analisar a maneira mais correta e flexível de calcular o tempo relativo em C#. Você receberá um código pronto que pode ser inserido diretamente no seu projeto, entenderá como ele funciona e aprenderá a personalizá-lo para qualquer necessidade.
\n\nO problema: o que há de errado com a simples subtração de datas?
\n\nA primeira coisa que vem à mente é subtrair uma data da outra e obter um TimeSpan. Sim, isso funciona. Mas o diabo está nos detalhes:
- \n
- Valores limite. Quando termina o "minuto" e começa a "hora"? E quando a "hora" se transforma em "dia"? \n
- Datas futuras. E se a data estiver no futuro? Mostrar "em 5 minutos" ou "em 1 dia"? \n
- Legibilidade do código. Se você espalhar a lógica por todo o projeto, em um mês você mesmo ficará confuso. \n
Portanto, não precisamos apenas de um trecho de código, mas de um método único e reutilizável.
\n\nSolução: método universal para cálculo de tempo relativo
\n\nA melhor maneira é escrever um único método estático que receba um DateTime (ou DateTimeOffset) e retorne uma string bonita. Aqui está uma implementação básica, mas já muito poderosa, que pode ser encontrada em discussões no Stack Overflow e adaptada às suas necessidades:
using System;\n\npublic static class TimeHelper\n{\n public static string GetRelativeTime(DateTime dateTime)\n {\n var now = DateTime.Now;\n var utcNow = DateTime.UtcNow;\n\n // Importante: comparar no mesmo fuso horário!\n var timeSpan = now - dateTime;\n\n // Caso 1: data no futuro\n if (timeSpan.TotalSeconds < 0)\n {\n // Calcula o valor absoluto para o futuro\n timeSpan = timeSpan.Duration();\n if (timeSpan.TotalMinutes < 1)\n return "em alguns segundos";\n if (timeSpan.TotalMinutes < 60)\n return $"em {timeSpan.Minutes} min.";\n if (timeSpan.TotalHours < 24)\n return $"em {timeSpan.Hours} h.";\n if (timeSpan.TotalDays < 30)\n return $"em {timeSpan.Days} dias";\n if (timeSpan.TotalDays < 365)\n return $"em {timeSpan.Days / 30} meses";\n return $"em {timeSpan.Days / 365} anos";\n }\n\n // Caso 2: passado\n if (timeSpan.TotalMinutes < 1)\n return "agora mesmo";\n if (timeSpan.TotalMinutes < 60)\n return $"{timeSpan.Minutes} min. atrás";\n if (timeSpan.TotalHours < 24)\n return $"{timeSpan.Hours} h. atrás";\n if (timeSpan.TotalDays < 7)\n return $"{timeSpan.Days} dias atrás";\n\n // Para datas com mais de uma semana, usamos dias\n if (timeSpan.TotalDays < 30)\n return $"{(int)timeSpan.TotalDays} dias atrás";\n if (timeSpan.TotalDays < 365)\n {\n int months = (int)(timeSpan.TotalDays / 30);\n return $"{months} meses atrás";\n }\n\n int years = (int)(timeSpan.TotalDays / 365);\n return $"{years} anos atrás";