using Nullable DateTime in C# - c#

I wanted to assign null value to DateTime type in c#, so I used:
public DateTime? LockTime;
When LockTime is not assigned LockTime.Value contains null by default.
I want to be able to change LockTime.Value to null after it has been assigned other value.

No, if LockTime hasn't been assigned a value, it will be the nullable value by default - so LockTime.Value will throw an exception if you try to access it.
You can't assign null to LockTime.Value itself, firstly because it's read-only and secondly because the type of LockTime.Value is the non-nullable DateTime type.
However, you can set the value of the variable to be the null value in several different ways:
LockTime = null; // Probably the most idiomatic way
LockTime = new DateTime?();
LockTime = default(DateTime?);

You could assign null directly to the variable (the Value property is readonly and it cannot be assigned a value):
LockTime = null;

Have you tried LockTime = null?

The Value porperty is readonly, so you can't assign a value to it. What you can do is to assign null to the LockTime field:
LockTime = null;
However, this will create a new DateTime? instance, so any other pieces of code having a reference to the original LockTime instance will not see this change. This is nothing strange, it's the same thing that would happen with a regular DateTime, so it's just something your code has to deal with gracefully.

DateTime? nullableDT = null;
Console.WriteLine("{0}\t{1}", nullableDT.HasValue, nullableDT);
nullableDT = DateTime.Now;
Console.WriteLine("{0}\t{1}", nullableDT.HasValue, nullableDT);
nullableDT = null;
Console.WriteLine("{0}\t{1}", nullableDT.HasValue, nullableDT);
/*
False
True 30.07.2010 11:17:59
False
*/

You can define the variable this way:
private Nullable<DateTime> _assignedDate;
_assignedDate = DateTime.Now;
and then assign a null value:
_assignedDate = null;

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;
}

How to set value type to null in c#?

I'm currently trying to set an int that is null, similar to how strings can be null. I've tried: int i = null; which returns Cannot convert null to 'int' because it is a non-nullable value type but string s = null; Is perfectly fine.
So value types by default can't be set to null, there are however ways to get them to set to null. To solve your issue you would need to do this:
int? i = null;
This comes from the Microsoft docs here:
https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/nullable-types/
Value Types versus Reference Types can be found here:
https://www.tutorialsteacher.com/csharp/csharp-value-type-and-reference-type
You can use question mark to make it nullable, like that:
int? x = null;
Console.WriteLine(x.Value);
This might help: make nullable reference types in c#
Just add ? to the end of the type
int? nullInt = null;
if (nullInt == null) {
Console.WriteLine("nullInt is null");
}

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# Determine difference between DateTime and DateTime? (Nullable)

I am trying to determine the difference between a DateTime and a DateTime? using reflection. Please see my test code below:
public class TestClass
{
public DateTime testDate1 { get; set; }
public DateTime? testDate2 { get; set; }
}
public void Test()
{
TestClass testing = new TestClass();
var props = typeof(TestClass).GetProperties();
foreach (PropertyInfo p in props)
{
object o = p.GetValue(testing);
if (typeof(DateTime?).IsInstanceOfType(o))
{
o = DateTime.Now;
}
if (typeof(DateTime).IsInstanceOfType(o))
{
if (((DateTime)o) == DateTime.MinValue)
{
o = null;
}
}
Console.WriteLine(string.Format("{0} = {1}", p.Name, (o ?? "NULL").ToString()));
}
}
The output of this code is the opposite to what i would expect. Currently the output is:
testDate1 = 26/01/2016 16:15:00
testDate2 = NULL
I am expecting testDate1 to be null and testDate2 to contain the value.
When debugging this code, it seems that the first pass using testDate1 passes both of the typeof if statements, the second fails both of the if statements. Can anybody help me understand and hopefully try and catch the specific nullable instance of the date time?
To note i have also tried switching to a definition and test on Nullable just in case, but it made no difference.
Many thanks!
First, keep in mind that testDate1 can never be null because DateTime is a struct. If you declare a DateTime without intitializing it, it will get the default value of DateTime.MinValue. testDate2, on the other hand, is a Nullable struct, where the default value is null(-ish... it's actually a value that represents null, but not null itself).
IsInstanceOfType is using o's GetType() method in the background to verify that its type is the same as the type you are comparing to (in this case, DateTime?). However, if you take a look at the documentation, it states:
Calling GetType on a Nullable type causes a boxing operation to be performed when the type is implicitly converted to Object. Therefore GetType always returns a Type object that represents the underlying type, not the Nullable type.
So, if you step through the foreach loop for the testDate1 property, you'll see that the first condition will return true (since testDate1 can't be null, which means it has to be of type DateTime). You then step into the second if-condition (though that's effectively just doing the same check again), but you don't enter the inner if because o currently has a value of DateTime.Now.
Now stepping through for testDate2 (which is holds a null value), you will see that you don't enter either of the if-conditionals because null doesn't have a type. As such, your object will remain null throughout the second iteration of the loop, giving you the output you see there.
NOTE: Just so you know, the way you're "assigning" values to o doesn't modify the original TestClass at all. Consider the following:
TestClass testing = new TestClass();
var prop = typeof(TestClass).GetProperty("testDate1");
// Here we get the current value of testing.testDate1, which is the default DateTime.MinValue
object o = prop.GetValue(testing);
// Here we set o to null... has ZERO effect on testing.testDate1.
o = null;
// What you actually want is probably the following.
// (Remember though that testDate1 can't be null... this just sets it back to DateTime.MinValue.)
prop.SetValue(testing, null);
The answer is you can't.
If you have an object date there is no way to know if it orginally comes from a nullabe DateTime or not.
DateTime? nullable = DateTime.Now;
object o = nullable;
The assignment to o is morally equivalent to
object temp = null;
if (nullable.HasValue)
{
temp = nullable.Value;
}
o = temp;
As you can see, the information of the nullable type is lost and what you are really getting is the boxed nullable's value.
This is easy to see by simply doing o.GetType() which will return DateTime if the nullable had a value or you will get a NullReferenceException if it didn't.
This does not mean that you can not determine if the declared type of a property, method or member is nullable or not. You can do this easily enough via reflection.
Thank you for so much useful comments and links. I realise that it was the property i should have been inspecting and not the object. I am using this:
Nullable.GetUnderlyingType(p.PropertyType)
It allows me to determine what i am dealing with and is pretty effective. I still end up switching on typeof(T).Name but i will cross that bridge when i come to it :)
I have to live with the fact that functional code vs ugly code remains an internal battle!

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