0

I am building a feature into my app that allows an event to scheduled into the future. IE: The event takes place every Wednesday at 6:30pm. I need to show the user, based on today's current date, when the NEXT Wednesday is.

If today is Thu Dec 6th 2018, it needs to show the user the next event is on "Wed Dec 12th, 2018 at 6:30pm"

If today is "Tuesday Jan 8th, 2019", it needs to show the user the next event is on "Wed Jan 9th, 2019 at 6:30pm"

The original start date is of the event is captured in my DB as the first day of the ongoing series. IE: Wed Sept 10, 2018. I am using that start date to try and calculate every next Wednesday.

  function nextEvent(cEvent) {
      var startDate = cEvent.ceDate+ ", " +cEvent.ceTime ;
      var ceDate = new Date(startDate) ;
      var curDate = new Date() ;
      var timeDiff = Math.abs(curDate.getTime() - ceDate.getTime()) ;
      var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24)) ;
      var addDays = Math.ceil(diffDays / 7) * 7 ;
      var futureDate = ceDate.setDate(ceDate.getDate() + addDays) ;
      var futureEvent = ceDate.format('D, M d, Y @ g:i a') ;
      return futureEvent ;
    }
  }

  // this date object START event is Wed Sept 10, 2018
  var dObject = {"ceDate":"2018-09-10","ceTime":"18:30:00"}
  var nextDate = nextEvent(dObject) ;

I am looping through several events, all using different start dates (ie: ceDate), and NEXT event is displaying the wrong next day. The example above (hard coded in dObject) is displaying Mon Dec 10, 2018, when it should be displaying Wed Dec 12, 2018.

As well, if today is Wednesday at 6pm, the next event still needs to show as TODAY at 6:30pm. The event lasts minimum 2 hours...so ideally I would also like to figure out how to show something like: Next Event: happening now til 8:30pm

rolinger
  • 2,787
  • 1
  • 31
  • 53
  • For adding and subtracting days, see [*How can I add 1 day to current date?*](https://stackoverflow.com/questions/9989382/how-can-i-add-1-day-to-current-date) You shouldn't do it by adding and subtracting milliseconds. – RobG Dec 06 '18 at 23:24

3 Answers3

0

Use moment, don't try an write your own date functions for anything more than simple calculations.

https://momentjs.com/

Find next instance of a given weekday (ie. Monday) with moment.js

Adrian Brand
  • 20,384
  • 4
  • 39
  • 60
0

There are a number of issues with your code. Given:

 var dObject = {"ceDate":"2018-09-10","ceTime":"18:30:00"}

then

var startDate = cEvent.ceDate+ ", " +cEvent.ceTime ;

will build a string like "2018-09-10, 18:30:00" which is not a format supported by ECMAScript, so when you do:

var ceDate = new Date(startDate);

the result is implementation dependent and may well result in an invalid Date.

Next:

var diffDays = Math.ceil(timeDiff / (1000 * 3600 * 24)) ;

appears to be trying to get the difference in days between two dates, however it doesn't accommodate the time component so 3 Nov 09:00 to 3 Nov 09:01 will be 1 day, even though it's on the same day and only 1 minute later.

Anyhow, taking your requirement of determining the next occurrence of a weekly event, you can get the event for the current week and if it's passed, add 7 days, e.g.

var dObject = {
  "ceDate": "2018-09-10", // Mon, 9 Sep 2018
  "ceTime": "18:30:00",
  "recurrenceUnit": "day",
  "recurrenceLength": 7
}

// Helper to parse ISO date as local
function parseISOLocal(s) {
  var b = s.split(/\D/);
  return new Date(b[0],b[1]-1,b[2]);
}

function nextEvent(obj) {
  // Get today's details
  var now = new Date();
  var day = now.getDay();

  // Get event details
  var evtDate = parseISOLocal(obj.ceDate);
  var evtDay = evtDate.getDay();
  
  // Set nextEvt to event for this week
  var nextEvt = new Date(+now);
  nextEvt.setHours(0,0,0,0);
  nextEvt.setDate(nextEvt.getDate() - day + evtDay);
  nextEvt.setHours(...obj.ceTime.split(/\D/));
  
  // If the nextEvent has passed, add 7 days
  // Should use the recurrenceUnit and recurrenceLength
  if (nextEvt < now) {
    nextEvt.setDate(nextEvt.getDate() + 7)
  }

  return nextEvt;
}

console.log(nextEvent(dObject).toString());

The source object needs to have the repeating period unit and multiple. I've added those but not used them, you should be able to see where it goes. You also need to have functions for add and subtracting hours, days, months, etc. to leverage them. There are plenty of questions and answers here already on those topics.

If I was designing a recurring event object, it would have a lot more information than above with methods to handle the various scenarios.

RobG
  • 142,382
  • 31
  • 172
  • 209
  • thanks for the detailed response. In what implementation would my concatenation of `ceDate+ ", " +ceTime` return an incorrect date object? – rolinger Dec 07 '18 at 14:02
  • @rolinger—Safari and Firefox, at least. But it's not so much if there's a case where it fails, but whether it's compliant with the language specification. There are now very few differences between them, but you shouldn't depend on standarised behaviour when there is a simple, standards compliant alternative. :-) – RobG Dec 07 '18 at 21:33
0

You could try the following:

const getNextOccurringDay = (date, dayOfWeek) => {
 date.setDate(date.getDate() + ((7 + dayOfWeek - date.getDay()) % 7));

 return date;
};

Where date is the date in which you want to locate the next occurring day from (i.e. today) and dayOfWeek is the next occurring day you're trying to find (i.e. if it's a Friday, then it would be 5, Wednesday would be 3, Saturday 6 etc.)

Please note this solution will return the current day if the day you're looking for is the same day as today (i.e. today is a Friday and you're looking for the next occurring Friday then today will be returned).

blueprintchris
  • 1,053
  • 1
  • 16
  • 38