skip to Main Content

I have been working with this code:

var rangesInputRange1 = [
    { startDate: parseDate("15/04/2024"), endDate: parseDate("01/05/2024") },
    { startDate: parseDate("01/06/2024"), endDate: parseDate("30/06/2024") }
];

var rangesInputRange2 = [
    { startDate: parseDate("01/04/2024"), endDate: parseDate("14/04/2024") },
    { startDate: parseDate("01/07/2024"), endDate: parseDate("31/08/2024") }
];

function parseDate(dateString) {
    var parts = dateString.split("/");
    return new Date(parts[2], parts[1] - 1, parts[0]);
}

function isDateInRanges(date, ranges) {
  return ranges.some(function(range) {
    return date >= range.startDate && date <= range.endDate;
  });
}

function countDaysInRange(startDate, endDate) {
  var oneDay = 24 * 60 * 60 * 1000;
  return Math.round(Math.abs((startDate - endDate) / oneDay));
}

jQuery('#start-date, #end-date').on('change', function() {
  var startDate = parseDate(jQuery('#start-date').val());
  var endDate = parseDate(jQuery('#end-date').val());

  var daysInRange1 = isDateInRanges(startDate, rangesInputRange1) ? countDaysInRange(startDate, endDate) : 0;
  var daysInRange2 = isDateInRanges(startDate, rangesInputRange2) ? countDaysInRange(startDate, endDate) : 0;

  var inputRange1 = jQuery('input.checkbox1');
  var inputNumber1 = jQuery('input.number1');
  var inputRange2 = jQuery('input.checkbox2');
  var inputNumber2 = jQuery('input.number2');

  inputRange1.prop('checked', daysInRange1 > 0).trigger('change');
  inputNumber1.val(daysInRange1).trigger('change');
  inputRange2.prop('checked', daysInRange2 > 0).trigger('change');
  inputNumber2.val(daysInRange2).trigger('change');
});

jQuery('#start-date, #end-date').trigger('change');

I have succeeded in if #start-date and #end-date are in same rangesInputRange. in this case, the code works fine.

How can I calculate daysInRange if the selected dates are in both rangesInputRange? (example: dates 10/04/2024 to 17/04/2024)

or selected dates are in part in only one rangesInputRange? (example: 28/08/2024 to 03/09/2024).

(date format: dd/mm/YYYY)

2

Answers


  1. Updated code for countDaysInRange function

    function countDaysInRange(startDate, endDate) {
      var daysInRange1 = isDateInRanges(startDate, rangesInputRange1) ? Math.min(countDays(startDate, endDate, rangesInputRange1), 0) : 0;
      var daysInRange2 = isDateInRanges(startDate, rangesInputRange2) ? Math.min(countDays(startDate, endDate, rangesInputRange2), 0) : 0;
    
      return daysInRange1 + daysInRange2;
    }
    
    function countDays(startDate, endDate, ranges) {
      return ranges.reduce(function (totalDays, range) {
        var overlapStartDate = startDate < range.endDate ? startDate : range.startDate;
        var overlapEndDate = endDate < range.endDate ? endDate : range.endDate;
    
        if (overlapStartDate <= overlapEndDate) {
          return totalDays + Math.round((overlapEndDate - overlapStartDate) / (1000 * 60 * 60 * 24));
        }
        return totalDays;
      }, 0);
    }
    

    The countDaysInRange function now calculates the number of days in both ranges separately and returns the total number of days calculated for overlapping or in-range periods.

    Update

    Updated Code

    I hope this will help.

    jQuery('#start-date, #end-date').on('change', function() {
      var startDate = parseDate(jQuery('#start-date').val());
      var endDate = parseDate(jQuery('#end-date').val());
    
      var daysInRange1 = isDateInRanges(startDate, rangesInputRange1) ? countDaysInRange(startDate, endDate, rangesInputRange1) : 0;
      var daysInRange2 = isDateInRanges(startDate, rangesInputRange2) ? countDaysInRange(startDate, endDate, rangesInputRange2) : 0;
    
      var inputNumber1 = jQuery('input.number1');
      var inputNumber2 = jQuery('input.number2');
    
      inputNumber1.val(daysInRange1).trigger('change');
      inputNumber2.val(daysInRange2).trigger('change');
    });
    
    // Separate countDaysInRange for each range
    function countDaysInRange(startDate, endDate, ranges) {
      return ranges.reduce(function(totalDays, range) {
        var overlapStartDate = startDate < range.endDate ? startDate : range.startDate;
        var overlapEndDate = endDate < range.endDate ? endDate : range.endDate;
    
        if (overlapStartDate <= overlapEndDate) {
          return totalDays + Math.round((overlapEndDate - overlapStartDate) / (1000 * 60 * 60 * 24));
        }
        return totalDays;
      }, 0);
    }
    
    Login or Signup to reply.
  2. Here is an alternative solution that will work with any number of date ranges. The function calc() calculates the array days that contains the number of says for each range that is touched by the time period entered by the user. For now it is simply printed to the console.

    function advD(d){ // advance a date object by one day
     d.setDate(d.getDate()+1); return d;}
    const ranges = [[ // using a slightly more standard way of predefining the date range dates
    { startDate: new Date(2024,3,15), endDate: new Date(2024,4,1) },
    { startDate: new Date(2024,5,1), endDate: new Date(2024,5,30) }
         ], [
    { startDate: new Date(2024,3,1), endDate: new Date(2024,3,14) },
    { startDate: new Date(2024,6,1), endDate: new Date(2024,7,31) }
    ]];
    
    const inps=[...document.querySelectorAll("[type=date]")];
    inps.forEach(inp=>inp.addEventListener("change",calc));
    
    function calc(){
     const [ustart,uend]=inps.map(d=>new Date(d.value));
     advD(uend);
     const days=ranges.map(r=>Math.round(r.reduce((a,c)=>
      a+Math.max(Math.min(c.endDate,uend)-Math.max(c.startDate,ustart),0)  
     ,0)/86400000)); // turn milliseconds into days for each range
     console.log(days);
    }
    
    ranges.flat().forEach(d=>advD(d.endDate));
    // calculate values for initial state of inputs:
    calc();
    <input type="date" name="start" value="2024-03-27">
    <input type="date" name="end" value="2024-05-07">
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search