views:

5099

answers:

5

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
            }
        }
    }
+2  A: 

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.

Matthew Jones
Your code will always return dateEffDateOne as a result, not a difference between the dates. I guess, it is not what @program247365 wants.
VladV
I don't believe that is what the OP asked for. He needs DateTime, but if he needs to store time periods, then he should be using TimeSpan.
Matthew Jones
+4  A: 

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);
Fredrik Mörk
> dateCurrentDate.Subtract(dateCurrentDate.Subtract(dateEffDateOne))dateCurrentDate-(dateCurrentDate-dateEffDateOne)==dateEffDateOneI guess, it is not what @program247365 wants.
VladV
@VladV: I think you are right. Since I have no clue how the various dates in the original code sample relates to each other I can't really figure out what result that is expected, so removed that line from my answer.
Fredrik Mörk
+1  A: 

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.

VladV
+1  A: 

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;
}
dahlbyk
Most excellent. Thank you very much!
program247365
A: 

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;
            }
        }
    }
program247365
You probably mean dateEffDateOne.Equals(DateTime.MinValue) rather than TimeSpan.Zero. In practice they're the same thing (stored as 0L), but you shouldn't rely on that coincidence.
dahlbyk
Gotcha. Thanks for the comment.
program247365