Microsoft.Data.Sqlite in .NET 10: DateTimeOffset Now Assumes UTC
You upgrade to .NET 10 — required before .NET 8 and 9 both hit end of support on November 10, 2026 — change no application code, and timestamps read back from SQLite are suddenly off by your server's UTC offset. No exception, no warning, no compiler error. The value is just different now.
// the exact behavior change, before and after
GetDateTimeOffset(), no offset in the datawas assumed local timezone → now assumed UTCDateTimeOffset to a REAL columnwas written as-is → now converted to UTC firstGetDateTime(), offset present in the datareturned DateTimeKind.Local → now returns DateTimeKind.Utcvar offset = reader.GetDateTimeOffset(0); // column stores "2026-01-15 10:30:00", no offset
2026-01-15T10:30:00+02:00 // assumed the server's local timezone
2026-01-15T10:30:00+00:00 // now assumed UTC -- a genuinely different instant in time
.NET 10 changed the assumption to align with SQLite's own convention: a timestamp with no offset is treated as UTC. It's arguably the more correct default -- SQLite itself has never assumed local time -- but "more correct" and "silent" is exactly what makes this dangerous for existing data written under the old assumption.
AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true);
// set this once at startup, before any SQLite connection is opened// why this is easy to miss
Nothing here throws. Tests that don't assert on the exact offset or DateTimeKind pass unchanged. The bug surfaces downstream — a scheduled report running at the wrong hour, an audit log timestamp that's off by a few hours, a comparison against DateTimeOffset.UtcNow that's now subtly wrong in the other direction than before. If timestamps out of SQLite look "shifted" by a consistent amount right after a .NET 10 upgrade, that consistent amount is very likely your server's UTC offset — and this is why.
// this lands in the same migration wave as the EF Core work
If you're moving to .NET 10 because of the November 2026 end-of-support deadline and also run EF Core migrations against the same database, the migrations-history mismatch covered here is worth checking in the same pass — both are the kind of change that doesn't show up until something's already been running in production for a while. For the general rules around UTC and epoch time this bug intersects with, see the Unix Timestamp & Epoch Time guide.
// frequently asked questions
What changed with DateTimeOffset in .NET 10's Microsoft.Data.Sqlite?
When a stored value carries no explicit offset, GetDateTimeOffset() now assumes UTC instead of the local timezone. Writing a DateTimeOffset to a REAL column is now converted to UTC first instead of written as-is. GetDateTime() with an offset present now returns DateTimeKind.Utc instead of DateTimeKind.Local. All three changed in the same release, silently — same code, same data, no exception.
Why don't I get an error when this SQLite timezone assumption changes?
Nothing throws. Tests that don't assert on the exact offset or DateTimeKind pass unchanged. The bug surfaces downstream instead — a scheduled report running at the wrong hour, an audit log timestamp off by a few hours. If timestamps out of SQLite look shifted by a consistent amount right after a .NET 10 upgrade, that consistent amount is very likely your server's UTC offset.
How do I revert to the old SQLite DateTimeOffset behavior in .NET 10?
AppContext.SetSwitch("Microsoft.Data.Sqlite.Pre10TimeZoneHandling", true), set once at startup before any SQLite connection is opened. This is documented as a temporary compatibility path, not a permanent fix — every day it stays on, new data keeps being written under the old local-time assumption.
// try it yourself
Convert between epoch, UTC, and local time directly with the Unix Timestamp / Epoch Converter to confirm exactly what offset a given stored value should resolve to before and after this change.
SQLite itself doesn't enforce timezone semantics — it stores timestamps as plain text or numbers and leaves interpretation to the client.
Microsoft.Data.Sqlitemakes an assumption when a stored value carries no explicit offset, and that assumption changed in .NET 10: