DateTime null values - c#

I have the following code that is supposed to check that a value in a data reader is not null. If it is then the method should return a null value or null DateTime for use later.
private static DateTime safeGetDateTime(OleDbDataReader dr, int idx)
{
if (!dr.IsDBNull(idx))
return dr.GetDateTime(idx);
else return DateTime.MinValue;
}
I have tried just returning null but as the methods return type is "DateTime", this did not work. I then tried to return DateTime.MinValue if a null is picked up by the datareader. This has given me the following error:
SqlDateTime overflow. Must be between 1/1/1753 12:00:00 AM and 12/31/9999 11:59:59 PM.
Any help is appreciated.

You get this error because of DateTime.MinValue differeneces in CLR and SQL server.
I suggest you to use Nullable Type

Let the method return a Nullable<DateTime>, then you can return null:
private static DateTime? safeGetDateTime(OleDbDataReader dr, int idx)
{
if (!dr.IsDBNull(idx))
return dr.GetDateTime(idx);
else
return null;
}
You still have to check the return value, your error suggests that you are using this value in another sql query as parameter, you have to assign DBNull.Value in the null-case.
DateTime? date = safeGetDateTime(reader, columnOrdinal);
yourSqlParameter.Value = date.HasValue ? (object)date.Value : DBNull.Value;

The error must come from you assigning DateTime.MinValue to a SqlDateTime parameter.
DateTime.MinValue:
The value of this constant is equivalent to 00:00:00.0000000, January 1, 0001.
SqlDateTime.MinValue
The minimum valid date for a SqlDateTime structure is January 1, 1753.
So if you are going to use the return of this method in a SqlDateTime parameter, you can try returning SqlDateTime.MinValue:
return (DateTime)System.Data.SqlTypes.SqlDateTime.MinValue;
Alternatively, you can try using DateTime? as the returning type, so you can return null

You can keep safeGetDateTime just as it is, but when you write the value back to the database, you should check if it is the DateTime.MinValue. If it is, then you should write a null value to the database.
if (value == DateTime.MinValue)
{
comm.Parameters.AddWithvalue("#mydate", null);
}
else
{
comm.Parameters.AddWithValue("#mydate", value);
}

Related

csharp Value of '01/01/0001 00:00:00' is not valid how to handle?

if (File.Exists(settingsFile))
{
string[] lines = File.ReadAllLines(settingsFile);
if (lines.Length > 0)
{
trackBarHours.Value = Convert.ToInt32(optionsfile.GetKey("trackbarhours"));
trackBarMinutes.Value = Convert.ToInt32(optionsfile.GetKey("trackbarminutes"));
trackBarSeconds.Value = Convert.ToInt32(optionsfile.GetKey("trackbarseconds"));
savedMilliseconds = Convert.ToInt32(optionsfile.GetKey("milliseconds"));
dateTimePicker1.Value = Convert.ToDateTime(optionsfile.GetKey("timetargetvalue"));
richTextBox1.Text = optionsfile.GetKey("result");
}
}
because the key "timetargetvalue" is not yet created in the settingsFile because i didn't saved it yet for the first time the value of the key of "timetargetvalue" is '01/01/0001 00:00:00'
in that case that there is no yet the key hwo can i handle the datetime exception ?
dateTimePicker1 is a DateTimePicker control.
the exception is on the line :
dateTimePicker1.Value = Convert.ToDateTime(optionsfile.GetKey("timetargetvalue"));
System.ArgumentOutOfRangeException: 'Value of '01/01/0001 00:00:00' is not valid for 'Value'. 'Value' should be between 'MinDate' and 'MaxDate'.
Parameter name: Value'
what should i check against of so it will not throw the exception ?
DateTimePicker.Value must be above DateTimePicker.MinimumDateTime, which is 'January 1, 1753'.
When you haven't set the timetargetvalue, it will resolve to '01/01/0001 00:00:00', as you have seen, which is too early.
So you need to check the value before assigning it to DateTimePicker.Value.
You can do it like this:
DateTime tempDateTime = Convert.ToDateTime(optionsfile.GetKey("timetargetvalue");
dateTimePicker1.Value = tempDateTime >= DateTimePicker.MinimumDateTime ? tempDateTime : DateTimePicker.MinimumDateTime;
When dealing with a Struct such as DateTime that does not have any value we need to consider that this is not a class and can not be set to null. It must always have some value. (see https://learn.microsoft.com/en-us/dotnet/api/system.datetime?view=net-7.0)
The exception mentions in a round about way that the range of acceptable values is between dateTimePicker1.MinDate and dateTimePicker1.MaxDate so one option is to check if your value is within this range. But it's unlikely to be the best option. (see https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datetimepicker.mindate?view=windowsdesktop-6.0)
I'm pretty sure that DateTime default value is equal to that of DateTime.Min but if you really wanted to check if the value is default then I would suggest comparing it to default(DateTime) would be better.
This pretty much covers the use of DateTime and value defaults when null is not an option. Which brings up a possibly more desirable option. Encapsulation.
We could instead encapsulate the DateTime struct into a Nullable class. The encapsulating class will be nullable and will also be able to present the encapsulated value through a property called Value. (see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/nullable-value-types)
There are two ways to declare such a Nullable class, both of which compile to the same thing:
Nullable<DateTime> myNullableDate = null;
DateTime? anotherNullableDate = null;
Since the DateTime is encapsulated in a Nullable object we can start using a null reference check. We can also call a method on Nullable called HasValue which returns a bool (True if it has a value).
EDIT: I notice that you're not doing any checks before trying to parse the DateTime and then directly setting it into the DateTimePicker.Value which can accept a null value. (although setting null won't clear a previously set value).
As such perhaps what you might want to do is handle the scenario a bit better and then use a DateTime.TryParse() instead. (see https://learn.microsoft.com/en-us/dotnet/api/system.datetime.tryparse?view=net-7.0)
e.g. (not the most optimized code, but I think it's easier to follow along in a more verbose form)
private DateTime? LoadDateFromOptions(string key)
{
var rawValue = optionsfile.GetKey(key);
if (!string.IsNullOrEmpty(rawValue))
{
return null;
}
DateTime dateValue;
bool isSuccess = DateTime.TryParse(rawValue, out dateValue);
if (isSuccess)
{
return dateValue;
}
else
{
return null;
}
}
and then instead of having that exception you can load the value optionally a bit more like this:
var timeTarget = LoadDateFromOptions("timetargetvalue");
if (timeTarget != null)
{
dateTimePicker1.Value = timeTarget;
}

Getting Time from DateTime

This is confusing, all I want is the Time from DateTime ?
here is my code:
clsdbo_RR.DateRecd = reader["DateRecd"] is DBNull ? null : (DateTime?)reader["DateRecd"];
clsdbo_RR.TimeRecd = reader["TimeRecd"] is DBNull ? null : reader["TimeRecd"].ToString("hh:mm:ss");
My date appears as date correctly but the time is not showing up?
private Nullable<DateTime> m_TimeRecd;
public Nullable<DateTime> DateRecd
{
get
{
return m_DateRecd;
}
set
{
m_DateRecd = value;
}
}
I strongly suspect that your reader["TimeRecd"] returns object, that's why you need to cast it to DateTime (or DateTime? as you did) first before you call ToString method. Without casting, it probably calls object.ToString method, not DateTime.ToString.
If your clsdbo_RR.TimeRecd is string, you just need to use (DateTime?)reader["TimeRecd"].ToString("hh:mm:ss") instead like;
clsdbo_RR.TimeRecd = reader["TimeRecd"] is DBNull ?
null : (DateTime?)reader["TimeRecd"].ToString("hh:mm:ss");

Assert Variable is not Null

I have a Variable with type DateTime?
In a Function I check it for being null and want to use it afterwards without always having to ?. every call. In e.g. Kotlin the IDE recognizes a check like that and asserts that the variable cannot be null afterwards. Is there a way to do this in C#?
DateTime? BFreigabe = getDateTime();
if (BFreigabe == null) return false;
TimeSpan span = BFreigabe - DateTime.Now;
//Shows Error because it.BFreigabe has the type DateTime?, even though it can't be null
Edit:
When using
TimeSpan span = BFreigabe.Value - DateTime.Now;
instead it works in this case because .Value doesn't have nullsafety at all. However, considering that this would compile even without the null check and just produce an error, the general question still remains. How can one persuade C# that a former nullable variable isn't nullable any more?
Edit 2
Casting DateTime on the Variable works.
TimeSpan span = (DateTime)BFreigabe - DateTime.Now;
Still not as safe as in Kotlin, but similar enough.
If you have the previous check, you can access the value. Nullable types always have two properties: HasValue and Value.
You could either cast to DateTime (Without the ?) or use the value property.
DateTime? BFreigabe = getDateTime();
if (!BFreigabe.HasValue == null)
return false;
TimeSpan span = BFreigabe.Value - DateTime.Now;
Or store the nullable variable in a non nullable variable:
DateTime? BFreigabe = getDateTime();
if (BFreigabe.HasValue == null)
{
DateTime neverNull = BFreigabe.Value;
TimeSpan span = neverNull - DateTime.Now;
}
This will get full editor support and guarantee that there is no NullReferenceExcpetion.
EDIT: Because your question states Assert. Assert usually means that we will throw an exception if the state is invalid.
In this case, omit the check for nullness. If you access var.Value while var is null, this will throw a NullReferenceException. This moves the responsibility to the caller.
Another option would be to not use the nullable variable. Either by converting it (see the second listing) or by not accepting Nullable types as a parameter.
function TimeSpan Calc(DateTime time)
{
// here we know for sure, that time is never null
}
How about this?
DateTime? BFreigabe = getDateTime();
if (!BFreigabe.HasValue) return false;
DateTime BFreigabeValue = BFreigabe.Value;
TimeSpan span = BFreigabeValue - DateTime.Now;
Try to convert NULL value to any value, that is irrelevant.
DateTime? BFreigabe = getDateTime();
if (BFreigabe == null) return false;
TimeSpan span = (BFreigabe??DateTime.Now) - DateTime.Now;

c# get and set accessors datetime

I am receiving unreachable code detected in my properties. This worked for regular string fields but not for DateTime data type.
private DateTime m_RenewalDate;
public DateTime M_RenewalDate
{
get { return m_RenewalDate != null ? m_RenewalDate : DateTime.MinValue; }
set { m_RenewalDate = value; }
}
this is my sqldatareader
reader.GetDateTime(reader.GetOrdinal("M_RENEWALDATE"))
DateTime is a value type, and can not be null. Therefore, the code in the getter is unreachable:
return m_RenewalDate != null ? // always evaluates to true
m_RenewalDate : // and therefore always returns this
DateTime.MinValue; // The code never hits this case.
If your field in the database can be null, perhaps you want to declare the property as a nullable DateTime: DateTime?.
DateTime is a value type and cannot be null. To compare with a null value in the database, use DBNull.Value
As driis said in his answer, m_RenewalDate == null is always false as DateTime is a value type and things declared to be value types cannot be null.
To have the get the behavior of returning DateTime.MinValue from M_RenewalDate in the case that M_RENEWALDATE is null your reader code should look more like this
object renewalDate = reader.GetValue(reader.GetOrdinal("M_RENEWALDATE"));
if (Equals(renewalDate, DBNull.Value))
{
yourObject.M_RenewalDate = DateTime.MinValue;
}
else
{
yourObject.M_RenewalDate = (DateTime) renewalDate;
}

Nullable Object must have a value #2

I'm trying to reuse the same code I've always used but now it is encountering an error.
I'm looping through various user tables, and in there I do this:
DateTime dcdt = (DateTime)u.DateCreated;
DateTime lldt = (DateTime)u.LastLogon;
userRow["DateCreated"] = dcdt.ToShortDateString();
inside the loop. I get the error:
System.InvalidOperationException: Nullable object must have a value.
The error highlights "lldt" line, instead of "dcdt" which comes first. That is strange in and of itself. Both these fields in the database "allow nulls" is checked. And they both could be null or neither might be null.
The two values are both listed as DateTime? types through intellisense.
I don't understand why ASP.NET refuses to allow me to output blank for null dates. If it is empty/null, then logic would suggest that ASP.NET should just print nothing.
How else am I suppose to output null dates? I tried adding if statements to prevent trying to cast null DateTimes, but it doesn't help, it makes no sense.
As you've said, the data type of u.LastLogon is DateTime?. This means that it may or may not have a value. By casting to DateTime, you are requiring it to have a value. In this case, it does not.
Depending on what you're trying to do with it, you may want to check the HasValue property:
userRow["LastLogon"] = u.LastLogin.HasValue ?
(object) u.LastLogin.ToShortDateString() : DBNull.Value;
If your database LastLogon column is of DateTime type, then you should be able to do:
userRow["LastLogon"] = u.LastLogin.HasValue ?
(object) u.LastLogin.Value : DBNull.Value;
You need to do something like the following in your data access code:
DataTable dt = ExecuteSomeQuery() ;
object value = dt.Rows[0]["nullable_datetime_column"] ;
DateTime? instance = value != null && value is DateTime ? (DateTime?)value : (DateTime?)null ) ;
If the column returned is NULL, it will be returned as a System.DBNull, otherwise it will be returned as an instance of DateTime (or whatever the appropriate mapped type is — int, string, etc). Consequently, you need to check the type of object returned from the query before trying to cast it.
Looks like you are trying to call a method (dcdt.ToShortDateString()) on a DateTime? which doesn't have a value (it is, indeed, null). Try this:
dcdt.HasValue ? dcdt.ToShortDateString() : String.Empty;
EDIT (Just re-read the question): Also, don't try to convert to DateTime. Preserve the nullable.
EDIT #2 (based on comments):
Try this:
if (dcdt.HasValue)
{ userRow["DateCreated"] = dcdt.ToShortDateString(); }
else
{ userRow = DbNull.Value }
I saw that Dexter asked how he should go about it. Well, I would create an extension.
static class DateTimeExtensions
{
public static string ToString(this DateTime? dateTime, string format)
{
return dateTime.HasValue ? dateTime.Value.ToString(format) : String.Empty;
}
}
And then you can do:
DateTime? dt = null;
DateTime? dt2 = DateTime.Now;
Console.WriteLine(dt.ToString("dd-MM-yy"));
Console.WriteLine(dt2.ToString("dd-MM-yy"));
Note that I can call extension method on a nullable type if the object is null.
The problem is .NET null is not the same as SQL NULL. SQL Null is System.DBNull. So it is a [non-null] value in .NET.
Short answer
DateTime? dateTime = u.LastLogon?.ToShortDateString()

Categories

Resources