AndreaNobili
AndreaNobili

Reputation: 42997

Some problems using ToShortDateString() method on a nullable DateTime object, why?

I have the following problem.

In a class I declare:

vulnerabilityDetailsTable.AddCell(new PdfPCell(new Phrase(currentVuln.Published.ToString(), _fontNormale)) { Border = PdfPCell.NO_BORDER, Padding = 5, MinimumHeight = 30, PaddingTop = 10 });

and the interesting part is: currentVuln.Published.ToString(). This work fine.

Published is a DateTime property declared as nullable, in this way:

public System.DateTime? Published { get; set; }

The problem is that in the previous way the printed value of currentVuln.Published.ToString() is something like 18/07/2014 00:00:00 (also the time is included in the date).

I want show only the date and not show the time so I tryed to use something like it:

currentVuln.Published.ToShortDateString()

But it don't work and I obtain the following error message in Visual Studio:

Error 4 'System.Nullable<System.DateTime>' does not contain a definition for 'ToShortDateString' and no extension method 'ToShortDateString' accepting a first argument of type 'System.Nullable<System.DateTime>' could be found (are you missing a using directive or an assembly reference?) C:\Develop\EarlyWarning\public\Implementazione\Ver2\PdfReport\PdfVulnerability.cs 93 101 PdfReport

It seems that this happen because my DateTime field is nullable.

What am i missing? How can I fix this issue?

Upvotes: 4

Views: 11452

Answers (3)

Grant Winney
Grant Winney

Reputation: 66469

You're right, it's because your DateTime field is nullable.

The extension methods for a DateTime are unavailable for DateTime?, but to understand why, you have to realize that there actually is no DateTime? class.

Most commonly, we write nullable types using the ? syntax, like DateTime?, int?, etc as you did above. But that's just syntactic sugar for Nullable<DateTime>, Nullable<int>, etc.

public Nullable<DateTime> Published { get; set; }

And all those apparently separate Nullable types come from a single generic Nullable<T> struct that wraps your type and provides two helpful properties:

  • HasValue (for testing whether the underlying wrapped type has a value), and
  • Value (for accessing that underlying value, assuming there is one)

Check to make sure there's a value first, then use the Value property to access the underlying type (in this case, a DateTime), along with any methods that are normally available for that type.

if (currentVuln.Published.HasValue)
{
    // not sure what you're doing with it, so I'll just assign it...

    var shortDate = currentVuln.Published.Value.ToShortDateString();
}

For C# 6.0 and higher you can use null conditional instead of .Value:

    var shortDate = currentVuln.Published?.ToShortDateString();

Upvotes: 16

Quintin
Quintin

Reputation: 41

Just in case someone else comes across this thread. You can use .value.ToShortDateString(). This will solve this issue.

Upvotes: 4

Jeppe Stig Nielsen
Jeppe Stig Nielsen

Reputation: 61982

The value type Nullable<> encapsulates a value of another value type together with a boolean hasValue.

This type Nullable<> inherits the method string ToString() from its ultimate base class, System.Object. It also overrides this method with a new implementation. The new implementation returns "" if hasValue is false, and returns the string it gets from .ToString() on the encapsulated value (which also inherits System.Object) if hasValue is true.

That is why your existing code is legal.

The type Nullable<> does not have any method ToShortDateString, though. You would have to go to the encapsulated value, through the Value property. Therefore, instead of the illegal:

currentVuln.Published.ToShortDateString()    /* error */

you will need

currentVuln.Published.HasValue ? currentVuln.Published.Value.ToShortDateString() : ""

or, equivalently

currentVuln.Published != null ? currentVuln.Published.Value.ToShortDateString() : ""

(both do the same at runtime). You could change the string "" to something else, like "never" or "not published" if you wanted.

If it could be a problem that the Published property (its get accessor) is called twice, you would need to take out a temporary variable somewhere, var published = currentVuln.Published;, and use that: published.HasValue ? published.Value.ToShortDateString() : ""

Upvotes: 2

Related Questions