question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

npgsql 6 breaks after DateTime migration: "year must be between 1 and 9999"

See original GitHub issue

After following the date migration guide to change types from “without time zone” to “with time zone”, I’m still having multiple errors. One of them occurs when reading rows from three of our tables:

Out of the range of DateTime (year must be between 1 and 9999)
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.DateTimeUtils.ReadDateTime(NpgsqlReadBuffer buf, DateTimeKind kind)
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.TimestampTzHandler.Read(NpgsqlReadBuffer buf, Int32 len, FieldDescription fieldDescription)
   at Npgsql.Internal.TypeHandling.NpgsqlTypeHandler.Read[TAny](NpgsqlReadBuffer buf, Int32 len, FieldDescription fieldDescription)
   at Npgsql.NpgsqlDataReader.GetFieldValue[T](Int32 ordinal)
   at Npgsql.NpgsqlDataReader.GetDateTime(Int32 ordinal)
   at Microsoft.EntityFrameworkCore.Query.Internal.SingleQueryingEnumerable`1.Enumerator.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at BarreleyeWebTest.BarreleyeIntegrationTestBase.<PrepareTestDatabase>b__17_0(BarreleyeDbContext context) in C:\Dev\BarreleyeServer\BarreleyeWebTest\BarreleyeIntegrationTestBase.cs:line 69

Inner exception:

Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. (Parameter 'ticks')
   at System.DateTime.ThrowTicksOutOfRange()
   at System.DateTime..ctor(Int64 ticks, DateTimeKind kind)
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.DateTimeUtils.DecodeTimestamp(Int64 value, DateTimeKind kind)
   at Npgsql.Internal.TypeHandlers.DateTimeHandlers.DateTimeUtils.ReadDateTime(NpgsqlReadBuffer buf, DateTimeKind kind)

My database contains some dates that I think were set to 0001/01/01 00:00:00, but which BeeKeeper (incorrectly) reports as 0001/12/31… and this breaks npgsql v6. As a workaround I have executed a series of queries like this to fix the problem:

UPDATE table_name
SET last_updated = date '0001-01-02'
WHERE last_updated < date '0001-01-02'

I think the problem can be fixed by changing this function in Npgsql\Internal\TypeHandlers\DateTimeHandlers\DateTimeUtils.cs:

    internal static DateTime DecodeTimestamp(long value, DateTimeKind kind)
        => new(value * 10 + PostgresTimestampOffsetTicks, kind);

do instead:

    internal static DateTime DecodeTimestamp(long value, DateTimeKind kind)
        => new(Math.Max(0, value * 10 + PostgresTimestampOffsetTicks), kind);

or maybe even:

    internal static DateTime DecodeTimestamp(long value, DateTimeKind kind)
        => new(Math.Max(0, Math.Min(DateTime.MaxValue.Ticks, value * 10 + PostgresTimestampOffsetTicks)), kind);

The other error I’m getting occurs when I create a fresh database by calling Migrate().

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:11 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
rojicommented, Dec 24, 2022

@TriHyde your case seems to be the same as @qwertie - please see the discussion above. You have negative timestamp data in your database, and that’s simply not representable with .NET DateTime. I recommend fixing up your data; for example, you could convert those values to -infinity with a single UPDATE command; after that, Npgsql will read those values as DateTime.MinValue.

If that isn’t suitable, can you please provide more on context on why, and how exactly you’re using those values?

0reactions
TriHydecommented, Dec 24, 2022

Can I reopen this?

I have old data in my database which causes a crash after upgrading to npgsql 6.

An example of a timestamp in the database (which the pgAdmin can read just fine) is “0001-01-01 00:00:00+01:39:49” (in pgAdmin view). pgAdmin does not crash but npgsql does, since it cannot READ that timestamp without throwing this particular exeption: “year must be between 1 and 9999”, inner: “Ticks must be between DateTime.MinValue.Ticks and DateTime.MaxValue.Ticks. (Parameter ‘ticks’)”.

Thanks!

Read more comments on GitHub >

github_iconTop Results From Across the Web

Date and Time Handling
.NET types and PostgreSQL types ; time without time zone, 1 microsecond, 0-24 hours, TimeOnly (6.0+), TimeSpan, 100 nanoseconds, -10,675,199 - 10,675,199 days....
Read more >
Out of the range of DateTime (year must be between 1 and ...
try to convert timestamp values from the database to DateTimeOffset . it represents wide range value that DataTime. use DateTimeOffset.
Read more >
Date, Time, and Time Zone Enhancements in .NET 6
I'm excited to share with you some of the improvements that have been made to .NET that are coming in .NET 6 in...
Read more >
How to Get SQL Server Dates and Times Horribly Wrong
One of the times that you need things to go right is when you are doing analysis and reporting. This is generally based...
Read more >
Using a PostgreSQL database as an AWS DMS source
With a PostgreSQL database as a source, you can migrate data to either another PostgreSQL database or one of the other supported databases....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found