[CS] CARLOS SEIDL PT
Articles

Avoid DateTime.Now in .NET 10 Production — UTC in the Cloud (Azure/AWS), Containers, and Best Practices

Store in UTC and display in local time: TimeProvider, containers with TZ=Etc/UTC, and best practices for Azure, AWS, and Kubernetes.

By 4 min read
  • .NET 10
  • UTC
  • Containers
  • Cloud
Article cover: Avoid DateTime.Now in Production

Project source: https://github.com/ceseidl/dotnet10-utc-docker

Why you should avoid DateTime.Now in distributed systems

In distributed systems, especially those hosted in the cloud (Azure/AWS) and running in containers, using DateTime.Now may seem harmless — but it’s a trap. It depends on the server’s local time zone, which causes inconsistencies between instances, problems with daylight saving time (DST), and makes testing harder.

⚠️ The problem with DateTime.Now

  • Dependence on the server’s local time
    If the server is set to a different time zone than you expect, your data can become inconsistent.
  • Environments with multiple time zones
    Global apps (users in several countries) suffer when each server uses a different local time.
  • Daylight saving time (DST) changes
    When the clock changes, calculations based on DateTime.Now can produce incorrect results.
  • Complicated testing and debugging
    Simulating scenarios with different time zones becomes a nightmare.

Real-world example
A payments system with users in India, the United Arab Emirates, and the US showed out-of-order transactions because servers (or replicas) were recording events with different local times.

Watch the video

O bug de horário que só aparece no horário de verão
Video in Portuguese on the ForgeTechPit channel: O bug de horário que só aparece no horário de verão

The solution: using UTC end to end in .NET

Store in UTC. Display in Local.

  • Use DateTime.UtcNow or TimeProvider.GetUtcNow() in your code.
  • Database and events always in UTC.
  • Convert to local time only in the UI (browser/app).
  • Configure the container with TZ=Etc/UTC and tzdata.

DateTime.Now in the cloud (Azure/AWS) and in containers

Architectures on Azure and AWS with AKS/EKS and ACA/ECS/Fargate scale horizontally; replicas may run in different regions. If each instance uses local time, inconsistencies appear. Therefore:

  • Standardize TZ in the container: ENV TZ=Etc/UTC + installing tzdata (when needed).
  • Apply UTC in code: never depend on DateTime.Now.
  • Logs and metrics: always in UTC; convert only at display time (dashboards).
  • Messaging (ASB/SQS/Kinesis): stamp events in UTC.

Recommended architecture for working with UTC

  • Client (Web/Mobile): displays the user’s local time.
  • .NET 10 API (pods/containers): runs with TZ=Etc/UTC, uses TimeProvider/UtcNow.
  • Services (Azure/AWS): messaging, databases, and observability in UTC.
  • Rule: Store in UTC. Display in Local. Tests with TimeProvider/FakeTimeProvider.

Example project structure using TimeProvider

Highlights:

  • src/ApiUtc/ → Minimal API with TimeProvider.
  • Dockerfile / Dockerfile.alpine → Ubuntu/Alpine with TZ=Etc/UTC.
  • docker-compose.yml → Port 8080 + healthcheck.
  • k8s/deployment.yml → AKS/EKS with a standardized TZ.
  • .github/workflows/ci.yml → CI/CD (.NET 10 build + push to GHCR via GITHUB_TOKEN).
  • README.md → article + diagram + references.

Project code: Minimal API, Dockerfile and CI

1) src/ApiUtc/ApiUtc.csproj (targets .NET 10)

2) src/ApiUtc/Program.cs (Minimal API + TimeProvider)

Note: with top‑level statements, type declarations must come after them.

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 (Option A — GHCR with GITHUB_TOKEN)

Key points for avoiding DateTime.Now in distributed environments

  • Standardize TZ in the container: ENV TZ=Etc/UTC + tzdata.
  • Apply UTC in code: DateTime.UtcNow, DateTimeOffset (explicit offset), and NodaTime for complex rules.
  • Messaging and jobs: timestamps always in UTC.
  • Observability: logs/metrics/traces in UTC (enrich with X-User-Timezone for dashboards).
  • Local conversion only in the UI: get the user’s time zone and convert on the front end.

How to run the example with Docker and Kubernetes

Docker (Ubuntu/Alpine)

Kubernetes (AKS/EKS)

GHCR (after CI)

Quick references on .NET 10, containers and TimeProvider

Summary: why adopt UTC and avoid DateTime.Now

Avoiding DateTime.Now is essential for global and distributed systems.
Adopting UTC in code, containers, and infrastructure prevents bugs, simplifies testing, and ensures consistency.

Want an architecture review of your .NET backend? See the backend and .NET architecture service.

← all articles