Problem with dates earlier than 1.1.1753
Description
Environment
Activity
0.7 was released
I kept DateType and TimeType just like they are.
The DateTimeType will no longer magically convert a value before 1753 to null. If that was a relied on feature you should convert the property to a NullableDateTime.
To get the most accurate use of System.DateTime use type="Timestamp" - see comments in class TimestampType for why.
Oh, to answer a question. The DateTime data type isn't nullable, so an unassigned value will be set to DateTime.MinDate.
For example:
public class MinDateTime
{
private static DateTime birthdate;
public static void Main( string[] args )
{
Console.WriteLine( birthdate.ToString() );
}
}
will return "1/1/0001 12:00:00 AM".
I think Microsoft's documentation is wrong. Their System.Data.OracleClient assembly has roughly (Reflector) this source for their DateTime type:
---------------8<---------------------
static OracleDateTime()
{
OracleDateTime.MaxValue = new OracleDateTime(DateTime.MaxValue);
OracleDateTime.MinValue = new OracleDateTime(DateTime.MinValue);
OracleDateTime.Null = new OracleDateTime(true);
}
---------------8<---------------------
I checked the MySQL driver source code, and the only min date check they have is:
---------------8<---------------------
public bool IsValidDateTime
{
get
{
return year != 0 && month != 0 && day != 0;
}
}
... followed by ...
public static explicit operator DateTime( MySqlDateTime val )
{
if (! val.IsValidDateTime) return DateTime.MinValue;
return val.GetDateTime();
}
---------------8<---------------------
Both are roughly respecting the .NET limitations of the DateTime type. I feel that following the MSDN documentation and restricting the minimum value to 1/1/1753 will create confusion. I strongly feel NHibernate should respect the boundaries of the native provider, or the .NET value boundaries if the native driver allows a wider range of values. By having each dialect specify a DateTime property for minimum and maximum values, both boundary exceptions are avoided and developers aren't surprised.
We had a hard time finding this bug, knowing that Oracle supports a date < 1/1/1753. It was out of sheer frustration that we tried "what if the Oracle driver was limited the same way as MS SQL Server?". Our jaws dropped when the tests confirmed it. Funny, it's not that we had any data going back that far, but the testers put in the .NET min date value and the app stopped returning data.
I myself think you should allow for all possible DateTime values to be persisted, and let the database handle any errors. Of course this isn't a database-independent solution, but in this case I think it's appropriate.
By the way, what happens when I have a varchar(10) column in the database, mapped to a string property, and try to save an 11-character string? NHibernate doesn't check this either. MySQL silently ignores the last character for example, other databases may be less forgiving.
What about just mapping DateTime to DbType.Date or maybe DbType.DateTime and TimeSpan to DbType.Time by default and letting the user adjust the DbType in the mapping file?
Oh, and why was DateTime.MinValue converted to null? It doesn't seem to be the case in my copy of NHibernate (but I modified it quite a bit, and MySQL Connector.NET too, so maybe I just didn't notice 🙂).
Sergey.
There is some hack in NHibernate related to handling of Time properties which assumes the earliest year for dates is 1753. This causes problems with Oracle (see http://sourceforge.net/forum/forum.php?thread_id=1189402&forum_id=252014) and also with MySQL, since both allow for dates earlier than year 1753.