Reputation: 4019
I'm converting a small MSAccess application to a web-based ASP.NET app, using C# 3.5. I was wondering what's the best way to work with dates in C#, when converting some of this VBA code over to C#.
Here is an example of the VBA Code:
Coverage1=IIf(IsNull([EffDate1]),0,IIf([CurrDate]<=[EndDate1],[CurrDate]-[EffDate1],[EndDate1]-[EffDate1]+1))
Here is what my current C# code looks like with the errors denoted in the commented code:
public DateTime CalculateCoverageOne(DateTime dateEffDateOne, DateTime dateCurrentDate, DateTime dateEndDateOne)
{
if (dateCurrentDate.Date <= dateEndDateOne.Date)
{
return null; //Get "cannot convert null to System.DateTime because it is a non-nullable value type" error
}
else
{
if (dateCurrentDate.Date <= dateEndDateOne)
{
return dateCurrentDate.Subtract(dateEffDateOne); //Gets error "cannot implicitly convert system.timepsan to system.datetime
}
else
{
return dateEndDateOne.Subtract(dateEffDateOne.AddDays(1)); //Gets error "cannot implicitly convert system.timepsan to system.datetime
}
}
}
Upvotes: 8
Views: 27742
Reputation: 77570
It looks like your VB is actually returning a time span, presumably in days. Here's the closest direct translation:
public TimeSpan CalculateCoverageOne(DateTime EffDate1, DateTime CurrDate, DateTime? EndDate1)
{
return (EndDate1 == null) ? TimeSpan.Zero :
(CurrDate < EndDate1) ? (CurrDate - EffDate1) :
(EndDate1.AddDays(1) - EffDate1);
}
If instead you just wanted a count of days, just return the TimeSpan's Days property:
public int CalculateCoverageOne(DateTime EffDate1, DateTime CurrDate, DateTime? EndDate1)
{
return ((EndDate1 == null) ? TimeSpan.Zero :
(CurrDate < EndDate1) ? (CurrDate - EffDate1) :
(EndDate1.AddDays(1) - EffDate1)).Days;
}
And for good measure, this is how I would clean up your final version:
public int CalculateCoverageOne(DateTime dateCurrentDate, DateTime dateEffectiveDate, DateTime dateEffDateOne, DateTime dateEndDateOne)
{
TimeSpan ts;
if (dateEffDateOne == DateTime.MinValue)
{
ts = TimeSpan.Zero;
}
else if (dateEffectiveDate <= dateEndDateOne)
{
ts = dateCurrentDate - dateEffDateOne;
}
else
{
ts = (dateEndDateOne - dateEffDateOne) + new TimeSpan(1, 0, 0, 0);
}
return ts.Days;
}
Upvotes: 3
Reputation: 4019
After some excellent answers (I've up-voted you guys), I've finally hammered out what I think is my answer. Turns out that returning an int, as the number of days, is what worked for me in this situation.
Thanks everyone, for providing your awesome answers. It helped me get on the right track.
public int CalculateCoverageOne(DateTime dateCurrentDate, DateTime dateEffectiveDate, DateTime dateEffDateOne, DateTime dateEndDateOne)
{
//Coverage1=
//IIf(IsNull([EffDate1]),0,
//IIf([CurrDate]<=[EndDate1],
//[CurrDate]-[EffDate1],
//[EndDate1]-[EffDate1]+1))
if (dateEffDateOne.Equals(TimeSpan.Zero))
{
return (TimeSpan.Zero).Days;
}
else
{
if (dateEffectiveDate <= dateEndDateOne)
{
return (dateCurrentDate - dateEffDateOne).Days;
}
else
{
return (dateEndDateOne - dateEffDateOne).Add(new TimeSpan(1, 0, 0, 0)).Days;
}
}
}
Upvotes: 1
Reputation: 158349
cannot convert null to System.DateTime because it is a non-nullable value type" error
The DateTime
type is a value type, which means that it cannot hold a null value. To get around this you can do one of two things; either return DateTime.MinValue
, and test for that when you want to use the value, or change the function to return DateTime?
(note the question mark), which is a nullable DateTime
. The nullable date can be used like this:
DateTime? nullable = DateTime.Now;
if (nullable.HasValue)
{
// do something with nullable.Value
}
cannot implicitly convert system.timepsan to system.datetime
When you subtract a DateTime
from another DateTime
, the result is a TimeSpan
, representing the amount of time between them. The TimeSpan
does not represent a specific point in time, but the span itself. In order to get the date, you can use the Add
method or the Subtract
method overload of a DateTime
object that accepts a TimeSpan
. Exactly how that should look I can't say, since I don't know what the different dates in your code represent.
In the last case, you can simply use the return value from the AddDays method, but with a negative value (in order to subtract one day, instead of adding one):
return dateEffDateOne.AddDays(-1);
Upvotes: 7
Reputation: 10359
DateTime is a value type. So, you cannot assign null to DateTime. But you can use a special value like DateTime.MinValue to indicate whatever you were trying to indicate by null.
DateTime represents a date (and time), like "July 22, 2009". This means, you shouldn't use this type to represent time interval, like, "9 days". TimeSpan is the type intended for this.
dateCurrentDate.Subtract(dateEffDateOne) (or, equivalently, dateCurrentDate-dateEffDateOne) is a difference between two dates, that is, time interval. So, I suggest you to change return type of your function to TimeSpan.
TimeSpan is also a value type, so you could use, for instance, TimeSpan.Zero instead of null.
Upvotes: 2
Reputation: 26190
Get the TimeSpan, then subtract that from the DateTime to get the date you want. For your inner IF statement, it would look like this:
TimeSpan estSpan = dateCurrentDate.Subtract(dateEffDateOne);
return dateCurrentDate.Subtract(estSpan);
EDIT: You may also want to return DateTime.MaxValue and have the calling function check for the max value, instead of returning null.
Upvotes: 3