Why can't I check if a 'DateTime' is 'Nothing'? - vb.net

In VB.NET, is there a way to set a DateTime variable to "not set"? And why is it possible to set a DateTime to Nothing, but not possible to check if it is Nothing? For example:
Dim d As DateTime = Nothing
Dim boolNotSet As Boolean = d Is Nothing
The second statement throws this error:
'Is' operator does not accept operands of type 'Date'. Operands must be reference or
nullable types.

This is one of the biggest sources of confusion with VB.Net, IMO.
Nothing in VB.Net is the equivalent of default(T) in C#: the default value for the given type.
For value types, this is essentially the equivalent of 'zero': 0 for Integer, False for Boolean, DateTime.MinValue for DateTime, ...
For reference types, it is the null value (a reference that refers to, well, nothing).
The statement d Is Nothing is therefore equivalent to d Is DateTime.MinValue, which obviously does not compile.
Solutions: as others have said
Either use DateTime? (i.e. Nullable(Of DateTime)). This is my preferred solution.
Or use d = DateTime.MinValue or equivalently d = Nothing
In the context of the original code, you could use:
Dim d As DateTime? = Nothing
Dim boolNotSet As Boolean = Not d.HasValue
A more comprehensive explanation can be found on Anthony D. Green's blog

DateTime is a value type, which is why it can't be null. You can check for it to be equal to DateTime.MinValue, or you can use Nullable(Of DateTime) instead.
VB sometimes "helpfully" makes you think it's doing something it's not. When it lets you set a Date to Nothing, it's really setting it to some other value, maybe MinValue.
See this question for an extensive discussion of value types vs. reference types.

DateTime is a value type, which means it always has some value.
It's like an integer - it can be 0, or 1, or less than zero, but it can never be "nothing".
If you want a DateTime that can take the value Nothing, use a Nullable DateTime.

Some examples on working with nullable DateTime values.
(See Nullable Value Types (Visual Basic) for more.)
'
' An ordinary DateTime declaration. It is *not* nullable. Setting it to
' 'Nothing' actually results in a non-null value.
'
Dim d1 As DateTime = Nothing
Console.WriteLine(String.Format("d1 = [{0}]\n", d1))
' Output: d1 = [1/1/0001 12:00:00 AM]
' Console.WriteLine(String.Format("d1 is Nothing? [{0}]\n", (d1 Is Nothing)))
'
' Compilation error on above expression '(d1 Is Nothing)':
'
' 'Is' operator does not accept operands of type 'Date'.
' Operands must be reference or nullable types.
'
' Three different but equivalent ways to declare a DateTime
' nullable:
'
Dim d2? As DateTime = Nothing
Console.WriteLine(String.Format("d2 = [{0}][{1}]\n", d2, (d2 Is Nothing)))
' Output: d2 = [][True]
Dim d3 As DateTime? = Nothing
Console.WriteLine(String.Format("d3 = [{0}][{1}]\n", d3, (d3 Is Nothing)))
' Output: d3 = [][True]
Dim d4 As Nullable(Of DateTime) = Nothing
Console.WriteLine(String.Format("d4 = [{0}][{1}]\n", d4, (d4 Is Nothing)))
' Output: d4 = [][True]
Also, on how to check whether a variable is null (from Nothing (Visual Basic)):
When checking whether a reference (or nullable value type) variable is null, do not use = Nothing or <> Nothing. Always use Is Nothing or IsNot Nothing.

In any programming language, be careful when using Nulls. The example above shows another issue. If you use a type of Nullable, that means that the variables instantiated from that type can hold the value System.DBNull.Value; not that it has changed the interpretation of setting the value to default using "= Nothing" or that the Object of the value can now support a null reference. Just a warning... happy coding!
You could create a separate class containing a value type. An object created from such a class would be a reference type, which could be assigned Nothing. An example:
Public Class DateTimeNullable
Private _value As DateTime
'properties
Public Property Value() As DateTime
Get
Return _value
End Get
Set(ByVal value As DateTime)
_value = value
End Set
End Property
'constructors
Public Sub New()
Value = DateTime.MinValue
End Sub
Public Sub New(ByVal dt As DateTime)
Value = dt
End Sub
'overridables
Public Overrides Function ToString() As String
Return Value.ToString()
End Function
End Class
'in Main():
Dim dtn As DateTimeNullable = Nothing
Dim strTest1 As String = "Falied"
Dim strTest2 As String = "Failed"
If dtn Is Nothing Then strTest1 = "Succeeded"
dtn = New DateTimeNullable(DateTime.Now)
If dtn Is Nothing Then strTest2 = "Succeeded"
Console.WriteLine("test1: " & strTest1)
Console.WriteLine("test2: " & strTest2)
Console.WriteLine(".ToString() = " & dtn.ToString())
Console.WriteLine(".Value.ToString() = " & dtn.Value.ToString())
Console.ReadKey()
' Output:
'test1: Succeeded()
'test2: Failed()
'.ToString() = 4/10/2012 11:28:10 AM
'.Value.ToString() = 4/10/2012 11:28:10 AM
Then you could pick and choose overridables to make it do what you need. Lot of work - but if you really need it, you can do it.

You can also use below just simple to check:
If startDate <> Nothing Then
your logic
End If
It will check that the startDate variable of DateTime datatype is null or not.

You can check this like below :
if varDate = "#01/01/0001#" then
' blank date. do something.
else
' Date is not blank. Do some other thing
end if

A way around this would be to use Object datatype instead:
Private _myDate As Object
Private Property MyDate As Date
Get
If IsNothing(_myDate) Then Return Nothing
Return CDate(_myDate)
End Get
Set(value As Date)
If date = Nothing Then
_myDate = Nothing
Return
End If
_myDate = value
End Set
End Property
Then you can set the date to nothing like so:
MyDate = Nothing
Dim theDate As Date = MyDate
If theDate = Nothing Then
'date is nothing
End If

Related

Set date variable to null

Dim dtIzvrsenja datetime
Private Sub chkDate_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkDate.CheckedChanged
If Me.chkDate.Checked Then
Me.dtpDate.CustomFormat = "dd.MM.yyyy"
Me.dtpDate.Enabled = True
dtIzvrsenja = dtpdate.value
Else
Me.dtpDate.CustomFormat = " "
Me.dtpDate.Enabled = False
dtIzvrsenja = Nothing
End If
End Sub
Is there any way to set the value of dtIzvrsenja to null if chk is not checked ?
Edit by using the way other mentioned.
{"Nullable object must have a value."}
Dim dtIzvrsenja2 As DateTime? = Nothing
dtIzvrsenja = dtIzvrsenja2
In order to support that, you need to use the generic Nullable(Of Date) type rather than just Date (the VB alias for the DateTime type). Normally, only reference type variables (Class type variables) support null values. Since Date is a value type variable (Structure), it doesn't support null. Nullable(Of T) allows you to wrap any value type and add support for null values to that type.
In VB (as well as C#, by the way), a question mark after any type name is shorthand for making the type nullable. So, Date? is equivalent to Nullable(Of Date). Here's your example code using nullables:
Dim dtIzvrsenja As Date?
Private Sub chkDate_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles chkDate.CheckedChanged
If Me.chkDate.Checked Then
Me.dtpDate.CustomFormat = "dd.MM.yyyy"
Me.dtpDate.Enabled = True
dtIzvrsenja = dtpdate.value
Else
Me.dtpDate.CustomFormat = " "
Me.dtpDate.Enabled = False
dtIzvrsenja = Nothing
End If
End Sub
However, the confusing thing about Nullable(Of T) is that it, itself, is not a reference type. Nullable(Of T) is a value type. So, even Nullable(Of Date) variables cannot be set to null in the traditional sense. What Nullable(Of T) does is it adds a HasValue As Boolean property which allows you to check if the value is null. Therefore, when you go to read the value of the variable, rather than first checking to see if the variable Is Nothing, you need to instead check to see if it's HasValue property is true. For instance:
If dtIzvrsenja.HasValue Then
Dim dtIzvrsenja2 As Date = dtIzvrsenja.Value
' ...
End If
If you really want to treat the Date type as a real reference type, then you can do so by declaring the variable As Object. Object variables are always reference variables, so when set to Nothing, they really are set to null. When you set an Object variable to a value-type value, such as a Date, it will box the value. When you read it's value and convert it back to a Date, it will go through a process called unboxing. This boxing/unboxing process does add some overhead, however. Also, the other downside of this is that the type-checking for code working with the Object variable will be skipped at compile-time. That means that, if you are not careful, you could get some exceptions at runtime if the variable references a type of object that is different than what you expect. You could avoid the type-checking issue by declaring your own class:
Public Class DateReference
Public Property Value As Date
End Class
Or:
Public Class Reference(Of T)
Public Property Value As T
End Class
However, that seems silly. Nullable(Of T) already serves that purpose, so unless you really need to make it a reference type, I'd suggest that you take the time to get acquainted with the standard way of doing it.
As a side note, another complication which further causes confusion in this area is that VB's Nothing keyword does not strictly mean null. It just means the deafult value for any type. So, for an Integer, Nothing equals the value zero. For a Date, it means Date.MinValue, etc.
Use Nullable:
Dim nullableDateValue As New Nullable(Of Date) = Nothing
You can also use the question mark (Nullable) specifier, though this is probably outmoded now...
Dim dtIzvrsenja As DateTime? = Nothing

VB .NET comparing strings

I don't get what's going on. The method equals doesn't work, and neither comparing the strings with the '=' operator or with 'string.compare'. thetruth is always set as "false".
Public Function ProcessLabel(myValue As Object) As String
If ((myValue Is DBNull.Value) = False) Then
Dim thetruth As Boolean
Dim myValueStr As String
myValueStr = CStr(myValue)
thetruth = String.Equals(myValueStr, "01/01/1900")
End If
Return myValue.ToString
End Function
I cannot attach images but I assure you, in myValueStr I have "01/01/1900".
I'm pretty sure that myValue is a Date object and not a string and that a database is involved where the minimum value is 01/01/1900, for example the SMALLDATETIME datatype. If you look at it in debugger you see it like 01/01/1900. But if you execute ToString( internally used on CStr(myValue)) you get the localized representation including the time portion, so something like 01.01.1900 00:00:00 (f.e. in germany).
Instead compare the right types:
If Not myValue Is DBNull.Value AndAlso Not myValue Is Nothing Then
Dim date = DirectCast(myValue, Date)
If date = New Date(1900, 01, 01) Then
End If
End If

Why is DateTime.MinValue a constant expression, but not DateTime.MaxValue in VB.NET?

I have a mammoth method signature as follows:
Public Shared Function GetChartData(Optional adHoc As Boolean = True, Optional startIndex As Integer = 0, Optional endIndex As Integer = Int32.MaxValue, _
Optional startTime As DateTime = DateTime.MinValue, Optional endTime As DateTime = DateTime.MaxValue, _
Optional deviceIds As List(Of Integer) = Nothing) As IEnumerable(Of ChartLinePoint)
The compiler only complains about endTime and says its default value, 'DateTime.MaxValue' must be a constant expression. It seems quite happy with startTime.
Both are not constants but Public Shared ReadOnly fields (evidence).
So even DateTime.MinValue is not accepted by the compiler as constant expression in an optional parameter:
Sub FooMethod(Optional d As DateTime = DateTime.MinValue)
'COMPILER ERROR '
End Sub
But you could use Nothing which means default value in VB.NET and DateTime.MinValue is the default:
Sub FooMethod(Optional d As DateTime = Nothing)
' works '
End Sub
It's also a viable approach to use a Nullable(Of DateTime) instead, all the more if Date.MinValue could be a valid value.
Sub FooMethod(Optional d As DateTime? = Nothing)
If d.HasValue Then
' use d.Value '
End If
End Sub
There is no mechanism to create const values of arbitrary value (or reference) types in .NET.
Only those types for which C#1 has literals, allowing initialisation of const fields, can have const values.
1 C# is used to write most of the base class library (BCL).

DateTime? Cannot assign a value

I need to have a property that is a nullable date as the datestamp is used for when a process is completed.
If there is no date this is a way to determain if the process has occured.
I have created a Nuallable DateTime property (DateTime?) however when i try to assign a value from my database entity(when debugged has a date value) i am not thrown an exception however my property still reads a null value after assignment.
How can i get a DateTime? type to accept a DateTime value? i thought this would do the trick _object.DateStamp (type = DateTime?) = _entity.DateStamp (Type = DateTime?, Value = DateTime) or for more understandable syntax
Ctype(object.DateStamp, DateTime?) = Ctype(entity.DateStamp, DateTime?)
Strange thing is i can assign the properties value like this.
Ctype(object.DateStamp, DateTime?) = Now
Oh btw im uisng LinQ Entities.
Any Help?
I had this same problem. I would assign a date from a user entered value and it would never assign to the Nullable Date property on my custom object. My solution was to assign the user entered value into a local Nullable date variable, and then assign that value to the property. Trying to cast the user entered value into a nullable type on a single line didn't work for me either. The solution that worked for me is below:
Dim MyDate As Date? = Date.Parse(Me.txtDate.Text.Trim())
MyObject.Date1 = AppearanceDateAlternate
Another way this can burn you is if you try to use the "<>" operator on a mixture of null and not-null.
Public Property OwnerSignoffDate As Date?
Get
Return _ownerSignoffDate
End Get
Set(value As Date?)
If value <> _ownerSignoffDate Then 'BAD!
_ownerSignoffDate = value
Dirty = True
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("OwnerSignoffDate"))
End If
End Set
End Property
change to:
Public Property OwnerSignoffDate As Date?
Get
Return _ownerSignoffDate
End Get
Set(value As Date?)
If value <> _ownerSignoffDate OrElse value.HasValue <> _ownerSignoffDate.HasValue Then 'GOOD!
_ownerSignoffDate = value
Dirty = True
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs("OwnerSignoffDate"))
End If
End Set
End Property

Make An Integer Null

I have an update function that updates an sql server db table through a dataset. One of the fields in the table is an integer and accepts null values. So when I am populating the update function I need a way to enter a null in when the function wants an integer.
I tried to do it this way but _intDLocation = "" throws an exception
Dim _dLocation As String = udDefaultLocationTextEdit.Text
Dim _intDLocation As Integer
If _dLocation <> "" Then
_intDLocation = Integer.Parse(udDefaultLocationTextEdit.Text)
Else
'NEED HELP HERE
_intDLocation = ""
End If
Integers cannot be set to Null. You have to make the integer "nullable" by adding a question mark after the word Integer. Now _intDLocation is no longer a normal integer. It is an instance of Nullable(Of Integer).
Dim _dLocation As String = udDefaultLocationTextEdit.Text
Dim _intDLocation As Integer?
If _dLocation <> "" Then
_intDLocation = Integer.Parse(udDefaultLocationTextEdit.Text)
Else
_intDLocation = Nothing
End If
Later on, if you want to check for null you can use this handy, readable syntax:
If _intDLocation.HasValue Then
DoSomething()
End If
In some cases you will need to access the value as an actual integer, not a nullable integer. For those cases, you simply access
_intDLocation.Value
Read all about Nullable here.
Try this:
Dim _dLocation As String = udDefaultLocationTextEdit.Text
Dim _intDLocation As Nullable(Of Integer)
If Not String.IsNullOrEmpty(_dLocation) Then
_intDLocation = Integer.Parse(_dLocation)
End If
My application uses a lot of labels that start out blank (Text property), but need to be incremented as integers, so I made this handy function:
Public Shared Function Nullinator(ByVal CheckVal As String) As Integer
' Receives a string and returns an integer (zero if Null or Empty or original value)
If String.IsNullOrEmpty(CheckVal) Then
Return 0
Else
Return CheckVal
End If
End Function
This is typical example of how it would be used:
Dim Match_Innings As Integer = Nullinator(Me.TotalInnings.Text)
Enjoy!
_intDLocation = Nothing