Fonte do projeto: https://github.com/ceseidl/dotnet10-utc-docker
Por que evitar DateTime.Now em sistemas distribuídos
Em sistemas distribuídos, especialmente hospedados em nuvem (Azure/AWS) e executados em contêineres, usar DateTime.Now pode parecer inofensivo — mas é uma armadilha. Ele depende do fuso horário local do servidor, o que causa inconsistências entre instâncias, problemas em horário de verão (DST) e dificulta testes.
⚠️ O problema com DateTime.Now
- Dependência do horário local do servidor
Se o servidor estiver com um fuso diferente do esperado, seus dados podem ficar inconsistentes. - Ambientes com múltiplos fusos horários
Apps globais (usuários em vários países) sofrem quando cada servidor usa horários locais distintos. - Mudanças de horário de verão (DST)
Quando o horário muda, cálculos baseados em DateTime.Now podem gerar resultados incorretos. - Testes e depuração complicados
Simular cenários com fusos diferentes se torna um pesadelo.
Exemplo real
Um sistema de pagamentos com usuários na Índia, Emirados Árabes e EUA apresentou transações fora de ordem porque servidores (ou réplicas) registravam eventos com horários locais diferentes.
Assista ao vídeo

A solução: usar UTC de ponta a ponta no .NET
Armazene em UTC. Exiba em Local.
- Use
DateTime.UtcNowouTimeProvider.GetUtcNow()no código. - Banco e eventos sempre em UTC.
- Converta para local apenas na UI (browser/app).
- Configure o contêiner com
TZ=Etc/UTCetzdata.
DateTime.Now na nuvem (Azure/AWS) e em contêineres
Arquiteturas em Azure e AWS com AKS/EKS e ACA/ECS/Fargate escalam horizontalmente; réplicas podem rodar em regiões diferentes. Se cada instância usa hora local, surgem inconsistências. Portanto:
- Padronize TZ no contêiner:
ENV TZ=Etc/UTC+ instalação detzdata(quando necessário). - Aplique UTC no código: nunca dependa de
DateTime.Now. - Logs e métricas: sempre em UTC; converta só na visualização (dashboard).
- Mensageria (ASB/SQS/Kinesis): carimbe eventos em UTC.
Arquitetura recomendada para trabalhar com UTC
- Cliente (Web/Mobile): exibe horário local do usuário.
- API .NET 10 (pods/containers): roda com
TZ=Etc/UTC, usaTimeProvider/UtcNow. - Serviços (Azure/AWS): mensageria, bancos e observabilidade em UTC.
- Regra: Store in UTC. Display in Local. Testes com TimeProvider/FakeTimeProvider.
Estrutura do projeto de exemplo com TimeProvider
Destaques:
src/ApiUtc/→ Minimal API com TimeProvider.Dockerfile/Dockerfile.alpine→ Ubuntu/Alpine comTZ=Etc/UTC.docker-compose.yml→ Porta 8080 + healthcheck.k8s/deployment.yml→ AKS/EKS com TZ padronizado..github/workflows/ci.yml→ CI/CD (build .NET 10 + push no GHCR viaGITHUB_TOKEN).README.md→ artigo + diagrama + referências.
Código do projeto: Minimal API, Dockerfile e CI
1) src/ApiUtc/ApiUtc.csproj (target .NET 10)
2) src/ApiUtc/Program.cs (Minimal API + TimeProvider)
Observação: com top‑level statements, as declarações de tipos devem vir depois.
3) Dockerfile (Ubuntu 24.04 “Noble” + TZ=Etc/UTC)
4) Dockerfile.alpine (Alpine + TZ=Etc/UTC)
5) docker-compose.yml
6) k8s/deployment.yml (AKS/EKS)
7) .github/workflows/ci.yml (Opção A — GHCR com GITHUB_TOKEN)
Pontos-chave para evitar DateTime.Now em ambientes distribuídos
- Padronize TZ no contêiner:
ENV TZ=Etc/UTC+tzdata. - Aplique UTC no código:
DateTime.UtcNow,DateTimeOffset(offset explícito) e NodaTime para regras complexas. - Mensageria e jobs: timestamps sempre em UTC.
- Observabilidade: logs/métricas/traces em UTC (enriqueça com
X-User-Timezonepara dashboards). - Conversão local só na UI: pegue o timezone do usuário e converta no front.
Como executar o exemplo com Docker e Kubernetes
Docker (Ubuntu/Alpine)
Kubernetes (AKS/EKS)
GHCR (após CI)
Referências rápidas sobre .NET 10, contêineres e TimeProvider
- .NET 10 lançado na .NET Conf 2025:
.NET Blog Recap · Anúncios .NET Conf 2025 - Containers .NET 10 (tags/OS):
.NET Docker — Imagens 10.0 GA - Porta 8080 default em ASP.NET containers:
Microsoft Artifact Registry — ASP.NET - TimeProvider (abstração de tempo):
Microsoft Learn - NodaTime (fusos horários):
NodaTime.org - Imagens oficiais e boas práticas:
Microsoft Learn — Official .NET Docker images
Resumo: por que adotar UTC e evitar DateTime.Now
Evitar DateTime.Now é essencial para sistemas globais e distribuídos.
Adotar UTC em código, contêineres e infraestrutura evita bugs, simplifica testes e garante consistência.
Leia também
- .NET 10 e C# 14: panorama do .NET 10, a versão usada no exemplo com TimeProvider.
- .NET 10 + Kubernetes: publica a API .NET em Kubernetes com probes, imagem enxuta e shutdown.
- Tolerância a Falhas vs Resiliência em .NET: cobre timeout, retry e circuit breaker para falhas em sistemas distribuídos.
Quer uma revisão da arquitetura do seu backend .NET? Conheça o serviço de backend e arquitetura .NET.
