2

I have some data as so from a datepicker:

$disabled_dates = "08/10/2017, 08/17/2017";
$start_date = "08/03/2017";
$num_of_weeks = "20";

I am trying calculate the end date based off the $start_date and $num_of_weeks

I know this is possible with new Date() but i'm not sure how to account for the $disabled_dates.

Peter Rakmanyi
  • 1,475
  • 11
  • 13
626
  • 1,159
  • 2
  • 16
  • 27
  • What do you need to account of? Its not clear to me. Should the disabled dates be ignored, and if so for the start or end? Should a date be added if they are found within the 20 week range? – Yolo Aug 03 '17 at 23:09

2 Answers2

3

strtotime() is an amazingly useful function for something like this. It accepts a wide variety of natural language and date/time inputs.

20 weeks from exactly now

echo date('c',strtotime('+20 weeks'))."\n";

20 weeks from the start of that day

echo date('c',strtotime('08/03/2017 +20 weeks'))."\n";

Your answer in php:

$disabled_dates = "08/10/2017, 08/17/2017";
$start_date = "08/03/2017";
$num_of_weeks = "20";

$the_end = strtotime($start_date.' GMT +'.$num_of_weeks.' weeks');

//make all the disabled dates into timestamps for easy comparison later
$disabled_dates_array = array();
foreach(explode(',', $disabled_dates) as $date){
  $disabled_dates_array[] = strtotime(trim($date).' GMT');
}

//now compare and delay the end date if needed
foreach($disabled_dates_array as $timestamp){
  //if there was a disabled date before the end, add a day's worth of seconds
  //strtotime() returns false if it can't parse the date, so make sure it's truthy
  if($timestamp && $timestamp <= $the_end){
    $the_end += 86400;
  }
}

$enddate = date('m/d/Y',$the_end);

Edit 1: added GMT to all strtotime() conversions, to avoid issues with daylight saving times changing the amount of seconds between dates. Some days are 23 hours and some are 25 because of daylight saving time. Leap seconds are not an issue in unix time.

Edit 2: Answer in javascript:

var disabled_dates = "08/10/2017, 08/17/2017";
var start_date = "08/03/2017";
var num_of_weeks = "20";

var the_end = Date.parse(start_date + ' GMT') + parseInt(num_of_weeks)*7*86400*1000;

//in javascript Date.parse is similar to php's strtotime,
//but it returns milliseconds instead of seconds
disabled_dates = disabled_dates.split(", ");
for(var i = 0, len = disabled_dates.length; i < len; i++){
  disabled_dates[i] = Date.parse(disabled_dates[i] + ' GMT');
  if(disabled_dates[i] && disabled_dates[i] <= the_end){
the_end += 86400000;
  }
}

the_end = new Date(the_end);
var enddate = ('0' + (the_end.getUTCMonth() + 1)).substr(-2) + '/' + ('0' + the_end.getUTCDate()).substr(-2) + '/' + the_end.getUTCFullYear();
console.log(enddate);

Here I ran into a problem with daylight saving time as

Sun Oct 29 2017 00:00:00 GMT+0100 (GMT Daylight Time) + 24 hours =
Sun Oct 29 2017 23:00:00 GMT+0000 (GMT Standard Time)

So adding ' GMT' (GMT Standard Time) at the end of the dates is important, otherwise the results may be off by a day.

This video gives some insight into how keeping time can become complicated.

Peter Rakmanyi
  • 1,475
  • 11
  • 13
1

I'm not sure if there is an easier way, but that's who I would do it:

// Put dates into array or split the string
$disabled = array(new DateTime('2012-08-01'),new DateTime('2017-09-19'));

$end_date = $date->add(new DateInterval('P'.$num_of_weeks.'D'));
$range = new DatePeriod($start_date, new DateInterval('P1D'),$end_date);

// remove disabled days
foreach($range as $date){
    if(in_array($date,$disabled))
        $end_date = $end_date->sub(new DateInterval('P1D'));
}

The Code is not tested but it should work. If not, let me know xD.

Hope that helps.

Marvin-wtt
  • 449
  • 6
  • 16