2

How the recurrence actually works is not a question. I want to implement a way to calculate the days between two dates with a specified recurrence interval. That could be weekly, monthly, bi-monthly(which I don't exactly know about) yearly etc. The simplest thing I have done until now is the following which let me count all the days between two dates and then loop through them with an interval of seven days for weekly recurrence. I would be grateful if you can suggest me the better and correct implementation of it. Thanks.

   //Push in the selected dates in the selected array.
                for (var i = 1; i < between.length; i += 7) {
                    selected.push(between[i]);
                    console.log(between[i]);

                }
Superman
  • 871
  • 2
  • 13
  • 31
  • Would look at using the date library moment.js to help with this. It has all sorts of date diff methods and add/subtract methods – charlietfl Jan 04 '15 at 06:43
  • @charlietfl I looked at number of libraries but I really want to implement my own code. You can say for learning. I believe this is not an overly complicated thing but is just I'm not a code nerd yet. – Superman Jan 04 '15 at 06:46
  • well ..to be honest..you aren't learning much if you are only as far along as you got and are already looking for others to provide solutions. WHat you have shown isn't comprehensive enough to help much with – charlietfl Jan 04 '15 at 06:47
  • Already got a working model of it. Need some assistance to make it fool proof. But totally agree with you. No one can learn coding by asking for exact solutions by others. :) @charlietfl – Superman Jan 04 '15 at 06:50

5 Answers5

3

Does this do something like what you're expecting? It would require an explicit argument for the number of days in the interval:

// startDate: Date()
// endDate: Date()
// interval: Number() number of days between recurring dates
function recurringDates(startDate, endDate, interval) {
  // initialize date variable with start date
  var date = startDate;
  // create array to hold result dates
  var dates = [];

  // check for dates in range
  while ((date = addDays(date, interval)) < endDate) {
    // add new date to array
    dates.push(date);
  }

  // return result dates
  return dates;
}

function addDays(date, days) {
  var newDate = new Date(date);
  newDate.setDate(date.getDate() + days);
  return newDate;
}

var startDate = new Date(2015, 0, 1);
var endDate = new Date(2016, 0, 1);
var interval = 20;
console.log(recurringDates(startDate, endDate, interval));

Here's the example on JSFiddle.

Dave N
  • 398
  • 1
  • 4
  • It looks good. My approach is almost the same. between array contains all the dates from start to end date. Then I loop on them with the interval of 7 days. But wasn't sure if it is the right way to do it. Just have a question if I want to exclude the weekends? Is there anyway to jog through them? I'm using jquery datepicker in this project. – Superman Jan 04 '15 at 08:58
  • The way I'm calculating gives me slightly different result. In your code start date got excluded from the range. Lets say range is this `var startDate = new Date(2015, 0, 1);` `var endDate = new Date(2015, 0, 21);` I got 01, 08 and 15. Your code gives 08 and 15. Which is the right result? interval is of 7 days. – Superman Jan 04 '15 at 09:01
  • @Superman that depends on whether you want the range to be inclusive of the start and end dates, which you did not specify in your question so I had to make an assumption. My code gives the dates in the range excluding the start and end dates. – Dave N Jan 04 '15 at 18:55
3

This function gives a date for every [interval] and [intervalType] (e.g. every 1 month) between two dates. It can also correct dates in weekends, if necessary. Is that what you had in mind?

Here a jsFiddle demo.

function recurringDates(startDate, endDate, interval, intervalType, noweekends) {
    intervalType = intervalType || 'Date';
    var date = startDate;
    var recurrent = [];
    var setget = {set: 'set'+intervalType, get: 'get'+intervalType};

    while (date < endDate) {
      recurrent.push( noweekends ? noWeekend() : new Date(date) );
      date[setget.set](date[setget.get]()+interval);
    }
    
    // add 1 day for sunday, subtract one for saturday
    function noWeekend() {
        var add, currdate = new Date(date), day = date.getDay();
        if (~[6,0].indexOf(day)) {
          currdate.setDate(currdate.getDate() + (add = day == 6 ? -1 : 1));
        }
        return new Date(currdate);
    }

    return recurrent;
}
KooiInc
  • 119,216
  • 31
  • 141
  • 177
  • what this tild sign is for? Its looking amazing but I need to get it through and understand the logic. Can you help me in it? – Superman Jan 04 '15 at 09:58
  • The tilde is a bitwise NOT operator. Here it's used as shorthand for `[6,0].indexOf(day))>-1`. The operator converts the expression to 0 (`falsy`) or a negative value (`truthy`). See also: http://www.javascriptturnsmeon.com/the-tilde-operator-in-javascript/ – KooiInc Jan 04 '15 at 10:00
  • Already just opened that link. :) You have some amazing coding skills. Impressed. ;) Any chance to get these dates selected on jquery datepicker? Working on it. However it is not the part of the question but curious to know if you can help me with it or gone through such thing already? – Superman Jan 04 '15 at 10:03
  • I don't really know jQuery datepicker. I suppose you can convert every date from the resulting array of dates to a datepicker element, or convert the array to a select element. Btw, I never really liked those datepickers, using my own keyboard based alternative (see http://jsfiddle.net/KooiInc/t62qcxzh/). – KooiInc Jan 04 '15 at 10:08
  • This is amazing. Without wasting your time anymore I would like to just ask you that please guide me to learn the javascript the way you did it and help me to enhance my coding skills. :) Please :P – Superman Jan 04 '15 at 10:16
  • Your above example isn't working in a new fiddle. Any reason? – Superman Jan 04 '15 at 10:17
  • You have to include a helper library: http://kooiinc.github.io/JSHelpers/Helpers-min.js (in the fiddle click 'External Resources' to add it). Btw: I've added a conversion to a select element to the original jsFiddle. – KooiInc Jan 04 '15 at 10:25
  • 1
    I'd like to teach you, but hey, that would take too much time ;) I have coded javascript for years and learned by reading a lot and much trial and error, suppose that's part of the secret. So, lots of stamina, Google, Stackoverflow, deciphering code from the ninja types should all take you further on the JS path ;). Not to forget: a very good teacher is *necessity* :). The alternative datepicker is used daily in a web application I'm involved with. – KooiInc Jan 04 '15 at 10:27
  • I'm on this quest with you Sir. Your twitter or any contact to stay in touch? Your fiddle, stack overflow and Git is already bookmarked. :) – Superman Jan 04 '15 at 10:30
  • Maybe some of my other jsfiddling can be of interest, see http://testbed.nicon.nl/fiddles.html. They're not all that great, it's just a bit of fiddling. I'm on twitter, suprisingly as @KooiInc, but not very active – KooiInc Jan 04 '15 at 10:34
  • This is also bookmarked already :) And please give me a contact to stay in touch with you. Microsoft messenger or google whatever. I think this fiddle is not giving the correct result. http://jsfiddle.net/Superman/8sr2zjd0/ – Superman Jan 04 '15 at 10:37
  • I suppose my info @SO http://stackoverflow.com/users/58186/kooiinc should give you the necessary contact info? – KooiInc Jan 04 '15 at 10:43
  • Hi, I don't know why I'm not able to get this [fiddle](http://jsfiddle.net/Superman/mtyscg5e/) working. – Superman Jan 05 '15 at 04:24
  • Use `recurringDates(new Date("2015/1/1"), new Date("2015/1/31"), 7, "Date", true)`. The function takes real dates as parameters. – KooiInc Jan 05 '15 at 05:40
  • Hey @kooiInc are you there? I want to show you some code to test it at your end. I'm facing some issues and also need some expert advice to make it better. – Superman Jan 05 '15 at 13:02
  • I sent you an email please have a look at it. Thanks. – Superman Jan 06 '15 at 13:34
2

If all you want is the number of recurrences, the fastest (constant time regardless of the size of the date range) is to do the following.

  1. Calculate the number of days in the date range. See formula below.

  2. Determine how many recurrences can fit in that number of days. This can be done with a simple division and floor operation. For instance, if the date range has 100 days, and you want a weekly recurrence, the number of recurrences is Math.floor(100 / 7)

It will help if you set the start of your date range to be the date of the first recurrence.

If you want to get the actual dates and also want to do things like excluding weekends or holidays, you need to iterate over the date range as follows.

// psuedo-code
d = start_date;
interval_days = recurrence_days;
n = 0;
while(is_same_day_or_before(d, end_date)) {
  if(not_an_excluded_day(d)) {
    print(d);
    n++;
  }
  d = add_days(d, interval_days)
}
print("There are " + n + " recurrences");

This approach will let you do things like excluding weekends and holidays, if necessary.

You can implement is_same_day_or_before(d1,d2) with a simple comparison like d1 <= d2. If d1 and d2 can be in different time zones, then you want a more sophisticated check that accommodates for day light savings adjustments, etc.

The add_days function is more straightforward.

function add_days(d,n) {
  var d = new Date(d.getTime());
  d.setDate(d.getDate() + n);
  return d;
}

Calculating the number of dates between two (javascript) dates

The answer here and copied below for reference gives you a fast and accurate way of doing this regardless of how large the date range is.

var _MS_PER_DAY = 1000 * 60 * 60 * 24;

// a and b are javascript Date objects
function dateDiffInDays(a, b) {
  // Discard the time and time-zone information.
  var utc1 = Date.UTC(a.getFullYear(), a.getMonth(), a.getDate());
  var utc2 = Date.UTC(b.getFullYear(), b.getMonth(), b.getDate());

  return Math.floor((utc2 - utc1) / _MS_PER_DAY);
}
Community
  • 1
  • 1
Shyam Habarakada
  • 15,367
  • 3
  • 36
  • 47
1

The code can be either implemented in your own logic like you did or can use libraries. I reused the library later.js for the recurrence functionality.

Rohith K
  • 1,433
  • 10
  • 15
0

You can first calculate the difference in milliseconds and then show the millisecond difference in other difference format like this:

    Date.daysBetween = function( date1, date2 ) {
  //Get 1 day in milliseconds
  var one_day=1000*60*60*24;

  // Convert both dates to milliseconds
  var date1_ms = date1.getTime();
  var date2_ms = date2.getTime();

  // Calculate the difference in milliseconds
  var difference_ms = date2_ms - date1_ms;
  //take out milliseconds
  difference_ms = difference_ms/1000;
  var seconds = Math.floor(difference_ms % 60);
  difference_ms = difference_ms/60; 
  var minutes = Math.floor(difference_ms % 60);
  difference_ms = difference_ms/60; 
  var hours = Math.floor(difference_ms % 24);  
  var days = Math.floor(difference_ms/24);

  return days + ' days, ' + hours + ' hours, ' + minutes + ' minutes, and ' + seconds + ' seconds';
}

//Set the two dates
var y2k  = new Date(2000, 0, 1);
var Jan1st2010 = new Date(y2k.getYear() + 10, y2k.getMonth(), y2k.getDate());
var today= new Date();
//displays "Days from Wed Jan 01 0110 00:00:00 GMT-0500 (Eastern Standard Time) to Tue Dec 27 2011 12:14:02 GMT-0500 (Eastern Standard Time): 694686 days, 12 hours, 14 minutes, and 2 seconds"
console.log('Days from ' + Jan1st2010 + ' to ' + today + ': ' + Date.daysBetween(Jan1st2010, today));
Aminul
  • 1,738
  • 2
  • 24
  • 42