Ravi Gupta
Ravi Gupta

Reputation: 6480

Safely adding/subtracting days to DateTime in C#

I have a function which takes two DateTime parameters and I have to add separate offsets to these date. I know that DateTime has a AddDays function to add days to a date and it throws an exception if DateTime is less than MinValue or greater than MaxValue.

Now I want to do a safe check whether adding/subtracting the following number of days to a DateTime can cause over/under flow or not.

safeStartDate = (startDate == DateTime.MinValue || startDate == DateTime.MaxValue) ? startDate : startDate.AddDays(startDateOffset);
safeEndDate = (endDate == DateTime.MaxValue || endDate == DateTime.MinValue) ? endDate : endDate.AddDays(enDateOffset);

By doing this, I am making it one level exception free but date can be DateTime.Max - 1 and while trying to add offset it throws an exception. I am looking a better way that whether the final values over/under flows without doing the actual calculation, in order to prevent exception.

Upvotes: 8

Views: 12750

Answers (4)

novic3
novic3

Reputation: 106

I guess you are looking for something like this

DateTime Now = DateTime.Now;
DateTime Max = DateTime.MaxValue;
Max.Subtract(Now);
int DaysToAdd = 1000;//or something else
if (Max.Day > DaysToAdd) Now.AddDays(DaysToAdd);//add        

Upvotes: 0

Rawling
Rawling

Reputation: 50184

You can use the following to check whether you can add a given number of days to a given DateTime without causing an overflow:

bool CanAddDays(DateTime dt, int days)
{
    double maxDaysToAdd = (DateTime.MaxValue - dt).TotalDays;
    double minDaysToAdd = (DateTime.MinValue - dt).TotalDays;
    return days <= maxDaysToAdd && days >= minDaysToAdd;
}

Upvotes: 5

Scroog1
Scroog1

Reputation: 3589

If catch is not called very often you can do:

try
{
    safeDate = dt.AddDays(days);
}
catch (ArgumentOutOfRangeException)
{
    safeDate = date;
}

Alternatively,

var maxDays = (DateTime.MaxValue - dt).TotalDays;
safeDate = (days <= maxDays) ? dt.AddDays(days) : dt;

Or if there are negative days:

var maxDays = (DateTime.MaxValue - dt).TotalDays;
var minDays = (DateTime.MinValue - dt).TotalDays;
return (minDays <= days && days <= maxDays) ? dt.AddDays(days) : dt;

Or just use the method from Rawling's answer: CanAddDays(dt, days) ? dt.AddDays(days) : dt

The try/catch version is about 25% faster if you don't catch and about 1000x slower if you do. So, if you expected to catch more than about 1 time in every 5000 uses, then use the second version.

Upvotes: 10

Alex Filipovici
Alex Filipovici

Reputation: 32571

You might consider the following method:

private static DateTime AddDays(DateTime dateTime, int days)
{
    var daysTimeSpanTicks = (new TimeSpan(days, 0, 0, 0)).Ticks;
    return (days >= 0) ?
        (DateTime.MaxValue.Ticks < dateTime.Ticks + daysTimeSpanTicks) ? dateTime : dateTime.AddDays(days) :
        (dateTime.Ticks + daysTimeSpanTicks < 0) ? dateTime : dateTime.AddDays(days);
}

A sample usage is:

DateTime date = DateTime.MinValue;
DateTime safe = AddDays(date, -100);

Upvotes: 0

Related Questions