Algorithm to Add or Subtract Days from a Date

Algorithm to add or subtract days from a date?

The easiest way is to actually write two functions, one which converts the day to a number of days from a given start date, then another which converts back to a date. Once the date is expressed as a number of days, it's trivial to add or subtract to it.

You can find the algorithms here: http://alcor.concordia.ca/~gpkatch/gdate-algorithm.html

Date algorithm - Add days without considering leap years

Here is an extension method that works. Will also work if you're adding or subtracting enough days to span multiple leap years.

    public static DateTime AddDaysWithoutLeapYear(this DateTime input, int days)
{
var output = input;

if (days != 0)
{
var increment = days > 0 ? 1 : -1; //this will be used to increment or decrement the date.
var daysAbs = Math.Abs(days); //get the absolute value of days to add
var daysAdded = 0; // save the number of days added here
while (daysAdded < daysAbs)
{
output = output.AddDays(increment);
if (!(output.Month == 2 && output.Day == 29)) //don't increment the days added if it is a leap year day
{
daysAdded++;
}
}
}
return output;
}

Why is this algorithm to get a date in the past with timestamps not working?

The short answer is if you're using moment.js, then use it for the whole calculation (see below).

Your algorithm for subtracting 3 days doesn't work because the algorithm is wrong. A "working" version of the OP code is at the bottom. Given:

var timestampMinus3Days = timestampNow - (timestampNow % (interval1H * 24 * 3)); 

where timestampNow is an ECMAScript time value and interval1H is 3.6e6 ms.

The time value is milliseconds since 1970-01-01 UTC (the ECMAScript epoch) and % is a remainder operator, which is like modulo but not quite.

The expression timestampNow % (interval1H*24*3) divides the time since the epoch by 3 days and gets the remainder, so you're setting the new date to an integer multiple of 3 days from 1 Jan 1970, not 3 days ago. So once every 3 days the calculation will return a date for 3 days ago, and on the other two days it will return a date for 1 or 2 days ago.

The remainder also includes the time in the current day UTC, so if you're getting 00:00:00 your timezone must be +0 (GMT or UTC). Others will get a time equivalent to their timezone offset and a date for the previous day if their offset from UTC is negative.

Here's how to do it with moment.js and avoid messing with time values:

// 3 days ago from nowconsole.log(moment().subtract(3, 'days').format('DD.MM.YYYY HH.mm.ss'));
// 3 days ago at the start of the dayconsole.log(moment().subtract(3, 'days').startOf('day').format('DD.MM.YYYY HH.mm.ss'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>

C++ Date Algorithm

Supposing you're doing it for learning (there are many date libraries out there)... what is the exact problem you have? The algorithm is not very complex indeed and sounds like:

  1. add the number of days to the day field of the date
  2. if the number of days is now bigger than the maximum allowed (e.g. your date is like april 134, 2014) then decrement the number of days with the number of days of the month and increment the month number: e.g. april has 30 days, so date becomes may 104 2014
  3. repeat step 2 until the number of days is ok for the month (june 73, july 43, august 12)

the tricky parts are that

  1. the number of days of february depends on the year with a strange rule (it's 29 if year%4==0 && (year%100!=0 || year%400==0), 28 otherwise).
  2. when incrementing the month you may get past december, in that case go back to january but increment the year

This is not the fastest approach (requires you to loop over the months) but it's not difficult to implement.



Related Topics



Leave a reply



Submit