2
\$\begingroup\$

Using the following HTML:

<input type="date" value="2015-07-26" name="startdate">
<input type="date" value="2015-07-29" name="enddate">

First, the JS calculates the number of days between two dates:

var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
var start = document.querySelector('[name="startdate"]').value;
var end = document.querySelector('[name="enddate"]').value;
var firstDate = new Date(start);
var secondDate = new Date(end);
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));

startdate is the name of the first input field and enddate is the name of the second field.

Date.prototype.addDays = function(diffDays) {
    var dat = new Date(this.valueOf());
    dat.setDate(dat.getDate() + diffDays);
    return dat;
};

function getDates(startDate, stopDate) {
    var dateArray = [];
    var currentDate = startDate;
    while (currentDate <= stopDate) {
        dateArray.push(currentDate);
        currentDate = currentDate.addDays(1);
    }
    return dateArray;
}

var dateArray = getDates(new Date(start), (new Date(start)).addDays(diffDays));

↑ That is the part of the script I'm not really contented with, because I can imagine that the code could have been written simpler.

for (i = 0; i < dateArray.length; i++) {
    var input = document.createElement('input');
    var br = document.createElement("br");
    input.setAttribute("value", dateArray[i]);
    input.setAttribute("type", "date");
    document.body.appendChild(input);
    document.body.appendChild(br);
}

↑ Finally, it'll create for each day (between two dates) an input field, plus an linebreak after each input.

By the way, it would be nice to use the date format "DD.MM.YYYY", instead of "YYYY-MM-DD".

// Calculate number of days between two dates
var oneDay = 24*60*60*1000; // hours*minutes*seconds*milliseconds
var start = document.querySelector('[name="startdate"]').value;
var end = document.querySelector('[name="enddate"]').value;
var firstDate = new Date(start);
var secondDate = new Date(end);
var diffDays = Math.round(Math.abs((firstDate.getTime() - secondDate.getTime())/(oneDay)));

Date.prototype.addDays = function(diffDays) {
   var dat = new Date(this.valueOf());
   dat.setDate(dat.getDate() + diffDays);
   return dat;
};

function getDates(startDate, stopDate) {
    var dateArray = [];
    var currentDate = startDate;
    while (currentDate <= stopDate) {
        dateArray.push(currentDate);
        currentDate = currentDate.addDays(1);
    }
    return dateArray;
}

var dateArray = getDates(new Date(start), (new Date(start)).addDays(diffDays));

// create input fields (for each date one field)
for (i = 0; i < dateArray.length; i++) {
    var input = document.createElement('input');
    var br = document.createElement("br");
    input.setAttribute("value", dateArray[i]);
    input.setAttribute("type", "date");
    document.body.appendChild(input);
    document.body.appendChild(br); // linebreak after each input field
}
<input type="text" value="2015-07-26" name="startdate">
<input type="text" value="2015-07-29" name="enddate">
<br><br>

\$\endgroup\$
  • 1
    \$\begingroup\$ Correct me if I'm wrong, but doesn't (new Date(start)).addDays(diffDays) == new Date(end)? In other words, aren't you just recalculating the end date, though you already have it? \$\endgroup\$ – cbojar Jul 26 '15 at 3:07
3
\$\begingroup\$

I wouldn't bother with calculating the difference - especially as it's not actually used for anything.

Instead I'd just do this:

var start = new Date(document.querySelector('[name="startdate"]').value),
    end = new Date(document.querySelector('[name="enddate"]').value),
    year = start.getFullYear(),
    month = start.getMonth()
    day = start.getDate(),
    dates = [start];

while(dates[dates.length-1] < end) {
  dates.push(new Date(year, month, ++day));
}

That'll give you a dates array beginning with the start date and continuing up to and including the end date.

From there, it's pretty much the same as now: Create and append input elements. I'm not sure I like the <br>, though. I imagine it's mostly for layout purposes, in which case I'm sure you could handle it better in CSS.

As for the date formatting, I don't know of a way to change that. Browser support for the date-type input is very poor so just be glad if you can use it at all. But since it's not widely supported, you'll probably want to use a cross-browser widget anyway, and in that case you'll likely have options for formatting the date.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Thanks for your answer! As I ran your code I get every second day (beginning with the start date)? jsfiddle.net/Lakg9nbk \$\endgroup\$ – Maximilian Fuchs Jul 26 '15 at 20:22
  • \$\begingroup\$ @MaximilianFuchs That's because you're doing ++day twice: Once when pushing to the array, and once when alerting. So you're incrementing the day twice in each iteration of the loop. Your array will thus contain the 1st, 3rd, 5th (etc.) dates, and your alerts will show the 2nd, 4th, 6th (etc.) dates. It works fine when fixed \$\endgroup\$ – Flambino Jul 26 '15 at 20:55
  • \$\begingroup\$ It wouldn't work if dates are separted by a year or a month. \$\endgroup\$ – Stefdelec Aug 6 '18 at 12:36
0
\$\begingroup\$

Rather than extracting an array of dates then iterating over them, it might make more sense to use a more functional approach and pass in the behavior you want.

First, let's clear off the unneeded cruft:

var start = new Date(document.querySelector('[name="startdate"]').value);
var end = new Date(document.querySelector('[name="enddate"]').value);

We have the start and the end, and that's all we need. It's not necessary to calculate the difference because we can just go until we are greater than the end date.

As to your addDays method, I recommend against monkey-patching built-in classes. Doing so could lead to confusing and nasty bugs down the road if multiple libraries try to make incompatible changes. In this case, it would be better to just use a function that takes the initial date in. (Though we won't even need it anyway.)

Since we won't be getting dates, I'm going to change the name of the function, and allow passing in a function (that I'm calling block) that will be called on each generated date.

// Call block on each date from startDate to endDate, inclusive
function forEachDateInRange(startDate, endDate, block) {
    for(var currentDate = new Date(startDate); currentDate <= endDate; currentDate.setDate(currentDate.getDate() + 1)) {
        block.call(null, new Date(currentDate));
    }
}

This uses the call method of Function to call the function with the given arguments (the null means that this will be null when the function is called). We pass in an new Date object so that the called function cannot change currentDate. We can then call our function with the behavior we want to pass in:

forEachDateInRange(start, end, function(date) {
    var input = document.createElement('input');
    var br = document.createElement("br");
    input.setAttribute("value", date);
    input.setAttribute("type", "date");
    document.body.appendChild(input);
    document.body.appendChild(br);
});
| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.