Standardize DateTime Handling To UTC In Dot Net Core 9

Standardize DateTime Handling To UTC In Dot Net Core 9

Use UTC in Your Models

Modify your model properties to always store and retrieve DateTime in UTC:

public class Order
{
    public int Id { get; set; }

    private DateTime _orderDate;

    public DateTime OrderDate
    {
        get => _orderDate;  // Always return in UTC
        set => _orderDate = DateTime.SpecifyKind(value, DateTimeKind.Utc).ToUniversalTime();
    }
}
        

Best Practices

? Use DateTime.UtcNow instead of DateTime.Now in your application logic:

DateTime nowUtc = DateTime.UtcNow;        

? Convert user-supplied dates to UTC before processing:

var userInput = DateTime.Parse("2025-03-10T15:30:00"); var utcTime = DateTime.SpecifyKind(userInput, DateTimeKind.Utc).ToUniversalTime();        

?? Why? This ensures that all dates in your application are internally stored and used in UTC.


2?? Force UTC in Entity Framework (Data Layer)

Use EF Core interceptors or hooks to automatically convert all DateTime fields to UTC before saving them in the database.

Using EF Core SaveChanges() Hook

Modify AppDbContext to convert all DateTime properties to UTC before saving:

public class AppDbContext : DbContext
{
    public override int SaveChanges()
    {
        ConvertDatesToUtc();
        return base.SaveChanges();
    }

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        ConvertDatesToUtc();
        return base.SaveChangesAsync(cancellationToken);
    }

    private void ConvertDatesToUtc()
    {
        foreach (var entry in ChangeTracker.Entries())
        {
            foreach (var property in entry.Properties)
            {
                if (property.Metadata.ClrType == typeof(DateTime) && property.CurrentValue != null)
                {
                    property.CurrentValue = DateTime.SpecifyKind((DateTime)property.CurrentValue, DateTimeKind.Utc).ToUniversalTime();
                }
            }
        }
    }
}
        

will now be stored in UTC format, regardless of how developers enter the data.


3?? Enforce UTC for API Requests & Responses (Presentation Layer)

When working with Web APIs, you need to ensure that all DateTime values sent/received are in UTC.

Use a Global JSON DateTime Converter

Create a custom JsonConverter to serialize and deserialize DateTime in UTC:

public class UtcDateTimeConverter : JsonConverter<DateTime>
{
    public override DateTime Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        return DateTime.SpecifyKind(reader.GetDateTime(), DateTimeKind.Utc);
    }

    public override void Write(Utf8JsonWriter writer, DateTime value, JsonSerializerOptions options)
    {
        writer.WriteStringValue(value.ToUniversalTime().ToString("o")); // ISO 8601 format
    }
}
        

Register it in Program.cs:

builder.Services.AddControllers() .AddJsonOptions(options => { options.JsonSerializerOptions.Converters.Add(new UtcDateTimeConverter()); });        

? Ensures that all API responses return DateTime in UTC ? Ensures that all incoming requests automatically convert dates to UTC


4?? Global Middleware to Enforce UTC (Middleware Layer)

You can create a custom middleware that converts all DateTime properties in API requests to UTC.

public class UtcEnforcementMiddleware
{
    private readonly RequestDelegate _next;

    public UtcEnforcementMiddleware(RequestDelegate next)
    {
        _next = next;
    }

    public async Task Invoke(HttpContext context)
    {
        if (context.Request.HasJsonContentType())
        {
            context.Request.EnableBuffering();
            var body = await new StreamReader(context.Request.Body).ReadToEndAsync();
            context.Request.Body.Position = 0;

            if (!string.IsNullOrEmpty(body) && body.Contains("DateTime"))
            {
                // Convert all DateTime fields to UTC
                body = Regex.Replace(body, @"\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3,7})?Z?",
                    match => DateTime.Parse(match.Value).ToUniversalTime().ToString("o"));
            }
        }

        await _next(context);
    }
}        

Register it in Program.cs:

app.UseMiddleware<UtcEnforcementMiddleware>();        

? Ensures that all API requests containing DateTime fields automatically get converted to UTC


5?? Enforce UTC in SQL Server (Database Layer)

If you're using SQL Server, you can store all DateTime values in UTC format by default.

Set Default UTC Column Values

ALTER TABLE Orders ADD CONSTRAINT DF_Orders_CreatedAt DEFAULT GETUTCDATE() FOR CreatedAt;        

? Ensures database-generated timestamps (like CreatedAt) are always in UTC


6?? Time Zone Handling for Users

If your application supports users in different time zones, store everything in UTC and convert to the user’s local time when displaying data.

Convert UTC to Local Time for Display

public static DateTime ConvertUtcToLocal(DateTime utcDate, string timeZoneId) { var timeZone = TimeZoneInfo.FindSystemTimeZoneById(timeZoneId); return TimeZoneInfo.ConvertTimeFromUtc(utcDate, timeZone); }        

? Stores data in UTC but converts for user display


Summary of Best Approaches

?? Domain Layer – Use DateTime.UtcNow ? Ensures UTC usage in business logic ? Requires manual enforcement in every instance

?? Data Layer – EF Core SaveChanges Hook ? Automatically converts DateTimes before saving ? Works only with EF Core

?? Presentation Layer – Custom JSON DateTime Converter ? Ensures API request/response is always in UTC ? Does not enforce UTC storage in the database

?? Middleware Layer – UTC Enforcement Middleware ? Converts all incoming and outgoing DateTimes automatically ? Slightly complex implementation

?? Database Layer – SQL Server GETUTCDATE() ? Ensures all database timestamps are in UTC ? Does not enforce UTC in API processing


Best Approach for a Large-Scale Application

  1. Use EF Core Hooks or Interceptors to store all DateTime values in UTC.
  2. Use a Global JSON Converter to ensure API communication is in UTC.
  3. Use Middleware to enforce UTC before processing requests.
  4. Set GETUTCDATE() as default in SQL Server for UTC consistency.

要查看或添加评论,请登录

Osama Nasir的更多文章

社区洞察