I discovered a very interesting little twist on the differences between the Today property and the Now property in the DateTime Class. I was working on something recently and using the built-in Compare method of the DateTime Type.
Essentially the user selected a date and I had a validation snippet that was supposed to check that they had not picked a future date. One of the ways they could choose their date was via a DateTimePicker control.
I thought that this code might do the trick:
If Date.Compare(DateTimePicker1.Value, Today) < 0 Then
Label1.Text = "Past Date (or Today)"
Else : Label1.Text = "Future Date"
End If
It seemed logical enough. Today, is, well, today, isn't it?
Not quite so, however. It turns out that if the user picks today's date from the DateTimePicker then this will fall into the "Future Date" category. Thinking it through, I realised that the DateTimePicker value doesn't just represent today's date; it also holds the exact time when the selection is made.
The Today Property of the DateTime class, however, has its Time value set to 00:00:00 on the day in question. So when the Date Compare method is fired up it compares the exact date and time of the two values. With the mathematical accuracy that we would expect of VB, it deduces that the DateTimePicker value is later than the Today value (unless by some incredible coincidence we happen to hit the DateTimePicker arrow as midnight strikes!).
There are various fixes for this little gotcha. My preferred one is to use the Now property of the DateTime class in place of Today. As you would expect, "Now" returns both a date and a time, so this can be accurately compared to the date and the time of the selected value from the DateTimePicker. This way the validation process works just fine.
If Date.Compare(DateTimePicker1.Value, Now) < 0 Then
Label1.Text = "Using Now: Past Date or Today"
Else : Label1.Text = "Using Now: Future Date"
End If
Not being able to resist playing around with it, I found that I also achieved the correct result using a TimeSpan:
Dim ts As TimeSpan
ts = (CType(DateTimePicker1.Value.Subtract(Today), TimeSpan))
If ts.TotalDays < 1 Then
Label1.Text = "Timespan: Past Date or Today's Date"
Else : Label1.Text = "Timespan: Future Date"
End If
And, before someone comments up to tell me this, yep, I know that the DateTimePicker has a MaxDate Property. I tried that and it does a good job of preventing users from selecting a future date, but it's hardly awash with user-friendly feedback - so that version didn't make the cut either.
Anyhow, if you find yourself in a situation sometime where these date comparison results are going askew, you might want to check that this particular gotcha didn't getcha. It's a fairly easy trap to fall into for the unwary.