- Home
- .NET tutorials
- Use EF Core to easily save dates as UTC & show in local time
Use EF Core to easily save dates as UTC & show in local time
Published: Tuesday 22 April 2025
Having trouble with time zones in your ASP.NET Core application?
If you use Entity Framework Core you can easily save dates as UTC in the database and then convert them back to your local time zone in your ASP.NET Core application.
This is particularly crucial if your application spans multiple time zones.
Introducing ValueConverters
A ValueConverter
allows you to translate an entity's value to a provider like a SQL Server database and then translate it back to the model for an ASP.NET Core application.
This is perfect for what we want as we can convert a time to UTC when saving it in the database and then convert it back to the local time zone when using it in the application.
How to create a ValueConverter
To make this work you need to create a new class, import the Microsoft.EntityFrameworkCore.Storage.ValueConversion
namespace and then inherit the ValueConverter
class.
The ValueConverter
class expects a Model
and Provider
generic type. As we are expecting a DateTime
type in the database and the application we can include that for both of them.
Then you need to override one of the ValueConverter
base constructors to do the conversion. This expects two parameters:
- The first parameter is the
ExpressionFrom
value and this is how you save the value to the database. We convert theDateTime
value to universal time. - The other parameter is the
ExpressionTo
value and this is how it is displayed in the application. You have to specify that theDateTime
kind is UTC as that is how it's saved in the database. Then it's a case of converting it to your local time zone.
Here is the code for our DateTimeUtcConverter
ValueConverter
.
// DateTimeUtcConverter.cs
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
public class DateTimeUtcConverter : ValueConverter<DateTime, DateTime>
{
public DateTimeUtcConverter() : base(
d => d.ToUniversalTime(),
d => DateTime.SpecifyKind(d, DateTimeKind.Utc).ToLocalTime()
)
{
}
}
How to apply it to a property
We have a Product
entity set up in our DbContext
which looks like this:
// Product.cs
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public DateTime Created { get; set; }
}
When creating a new Product
entity in the database, if we were to set the Created
property to DateTime.Now
, it would save the DateTime
in the database using the application's local time zone. This would become problematic if you ever changed the time zone for your application.
But configuring the Product
entity allows us to specify the DateTimeUtcConverter
class in the HasConverter
extension method. This ensures that the Created
property will be stored as UTC in the database, and converted back to the local time zone when used in the application.
// ProductConfiguration.cs
public class ProductConfiguration : IEntityTypeConfiguration<Product>
{
public void Configure(EntityTypeBuilder<Product> builder)
{
builder.HasKey(s => s.Id);
builder.Property(s => s.Created)
.HasColumnName("CreatedUtc")
.HasColumnType("datetime")
.HasConversion(new DateTimeUtcConverter());
}
}
What about applying it for all DateTime
's?
If you have multiple DateTime
properties that need to be stored as UTC in the database, it could be time consuming to add the converter to each of the properties. As well as that, you're reliant on future code deployments where DateTime
properties are added to include the converter as part of the configuration.
However, there is a way you can apply it to all DateTime
properties in your DbContext
. To do that, you need to override the OnModelCreating
method in your DbContext
, create a new instance of DateTimeUtcConverter
and loop through each entity and each of its properties. You can apply your DateTimeUtcConverter
instance to that property if its CLR property is a DateTime
type.
// EfCoreDbContext.cs
public class EfCoreDateTimeDbContext : DbContext
{
...
/// <inheritdoc/>
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
...
var dateTimeUtcConverter = new DateTimeUtcConverter();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType == typeof(DateTime))
{
property.SetValueConverter(dateTimeUtcConverter);
}
}
}
base.OnModelCreating(modelBuilder);
}
}
Nullable DateTime
's
If you have nullable DateTime
properties you won't be able to use the DateTimeUtcConverter
as it is. You'll need to create a new ValueConverter
.
We have created a new DateTimeUtcNullableConverter
class which once again inherits the ValueConverter
class. But for the two generic types, we've provided nullable DateTime
types for both the Model
and Provider
.
We are also checking whether the date has a value when providing the ExpressionFrom
and ExpressionTo
parameters and passing back the original instance if it doesn't.
// DateTimeUtcNullableConverter.cs
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
public class DateTimeUtcNullableConverter
: ValueConverter<DateTime?, DateTime?>
{
public DateTimeUtcNullableConverter() : base(
d => d.HasValue ? d.Value.ToUniversalTime() : d,
d => d.HasValue ? DateTime.SpecifyKind(d.Value, DateTimeKind.Utc).ToLocalTime() : d)
{
}
}
If you want to apply it to all nullable DateTime
properties in your DbContext
, you can override the OnModelCreating
method in the DbContext
and check if the CLR type is a nullable DateTime
.
// EfCoreDateTimeDbContext.cs
public class EfCoreDateTimeDbContext : DbContext
{
...
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
var dateTimeUtcConverter = new DateTimeUtcConverter();
var dateTimeUtcNullableConverter = new DateTimeUtcNullableConverter();
foreach (var entityType in modelBuilder.Model.GetEntityTypes())
{
foreach (var property in entityType.GetProperties())
{
if (property.ClrType == typeof(DateTime))
{
property.SetValueConverter(dateTimeUtcConverter);
}
if (property.ClrType == typeof(DateTime?))
{
property.SetValueConverter(dateTimeUtcNullableConverter);
}
}
}
}
}
Watch the video
Watch our video where we show you how to add the DateTimeUtcConverter
class to your DbContext
and give you a demo on how it works. You'll have an understanding of how the date is stored in the database and how it's displayed in the application.
Related tutorials
