Environment: Visual Studio 2015
TimeZone:: UTC + 7:00, Bangkok
Issue: On DateTimeOffset nullable varialbe (DateTimeOffset?), the use of Null Conditional operator results in exception i.e. it still calls the method even if the value is NULL i.e. (value as DateTimeOffset?)?.ToLocalTime(), it calls the ToLocalTime and results in exception.
Query: I can resolve it by not using the Null conditional operator or using the GetValueOrDefault instead of the operator but I want to understand why it resutls in exception with all UTC + TimeZones, it works well with UTC - TimeZones
Code:
var dateTimeMinimum = DateTime.MinValue;
var value = (object)dateTimeMinimum; // Mimic the WPF converter behavior
var a1 = value as DateTimeOffset?; // This works
if (a1 != null)// This works as it won't execute the code in the 'if'loop
{
var b1 = (a1 as DateTimeOffset?)?.ToLocalTime();
}
var dto = (value as DateTimeOffset?)?.ToLocalTime() ?? (DateTime)value;// This breaks with following exception
EDIT:
I understand there are many ways to fix the code i.e.
DateTime dateTimeMinimum = DateTime.SpecifyKind(DateTime.MinValue, DateTimeKind.Utc);
Here's my query though, when I do not use the null conditional operator
var a1 = value as DateTimeOffset?;
It does not result in exception. Is it because the null conditional operator unwraps the variable per following blog
http://www.ninjacrab.com/2016/09/11/c-how-the-null-conditional-operator-works-with-nullable-types/
I am more interested in understanding why it breaks when I use null conditional operator and works when I simple cast if using the 'as' operator without using the DateTimeKind.Utc
EDIT2:
This is the constructor of DateTimeOffset (.NET framework code) and it breaks at ValidateOffset method. Source - http://referencesource.microsoft.com/#mscorlib/system/datetimeoffset.cs,68b4bb83ce8d1c31
// Constructs a DateTimeOffset from a DateTime. For Local and Unspecified kinds,
// extracts the local offset. For UTC, creates a UTC instance with a zero offset.
public DateTimeOffset(DateTime dateTime) {
TimeSpan offset;
if (dateTime.Kind != DateTimeKind.Utc) {
// Local and Unspecified are both treated as Local
offset = TimeZoneInfo.GetLocalUtcOffset(dateTime, TimeZoneInfoOptions.NoThrowOnInvalidTime);
}
else {
offset = new TimeSpan(0);
}
m_offsetMinutes = ValidateOffset(offset);
m_dateTime = ValidateDate(dateTime, offset);
}
