program247365
program247365

Reputation: 4019

Convert the TimeSpan datatype to DateTime?

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

Answers (5)

dahlbyk
dahlbyk

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

program247365
program247365

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

Fredrik M&#246;rk
Fredrik M&#246;rk

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

VladV
VladV

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

Matthew Jones
Matthew Jones

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

Related Questions