0

Must check if a collection of projects contains a startDate that has passed 3, 6, and so on, months, using moment.js but having problems coming up with a way to calculate the difference in time between today and startDate, was thinking of seeing if (today / startDate) % 3 === 0 but I don't think that's the best way and the results are not as expected. Even using moment.js diff, like this doesn't yield desired results and logs projects that clearly haven't elapsed elapsed 3, 6 etc... months. Obviously I'm missing something would appreciate some help thank you.

const today = moment()

const projects = await ProjectModel.find()
projects.forEach(project => {
    if (today.diff(moment(project.startDate), "month") % 3 == 0) {
        console.log(project)
    }
})

ImInYourCode
  • 406
  • 4
  • 15
  • `%` is not modulo, it's [*remainder*](https://stackoverflow.com/questions/37005330/what-is-the-operator-in-javascript). `x % 3` it doesn't tell you 3, 6, 9 months etc. it only tells you the remainder if you divide x by 3, e.g. 4%3 and 10%3 both give 1. – RobG Aug 12 '19 at 11:57
  • 1
    @RobG, you're right that `%` is used to calculate the remainder, and that's just another word for modulo. (See https://math.stackexchange.com/questions/1285043/how-to-calculate-a-modulo and https://en.wikipedia.org/wiki/Modulo_operation.) "In computing, the modulo operation finds the remainder after division of one number by another (called the modulus of the operation)." – Cat Aug 12 '19 at 16:31
  • 1
    @Cat—the [ECMAScript % operator](http://ecma-international.org/ecma-262/10.0/#sec-applying-the-mod-operator) does not conform to the mathematic definition of modulo (ECMAScript uses the sign of the dividend, modulo uses the sign of the divisor), hence it's called remainder. A link to an explanation is included in my first comment, see the accepted answer. Neither of your links is authoritative or address the ECMAScript % operator with respect to the modulo operation. – RobG Aug 12 '19 at 22:57
  • Thanks @RobG. I learned something today. They're similar, but that doesn't make them the same. – Cat Aug 13 '19 at 00:16

2 Answers2

2

% is the wrong way to go about it. You want to find the 3 month ago bracket that the date falls in, so get the difference in months and divide by 3 and floor the result. If diff < 3, you'll get 0. If 3 <= diff <6 months, you'll get 1, etc.

E.g.

let projects = [
 {startDate: new Date(2017,10,1)}, // 1 Nov 2017
 {startDate: new Date(2018,10,1)}, // 1 Nov 2018
 {startDate: new Date(2019, 0,1)}, // 1 Jan 2019
 {startDate: new Date(2019, 3,1)}, // 1 Apr 2019
 {startDate: new Date(2019, 4,1)}, // 1 May 2019
 {startDate: new Date(2019, 6,1)}, // 1 Jul 2019
 {startDate: new Date(2019, 7,1)}  // 1 Aug 2019
];
let today = moment();

projects.forEach(project => {
  let diff = today.diff(moment(project.startDate), "month") / 3 | 0;
  console.log(
    moment(project.startDate).format('DD-MMM-YYYY') +
    ' was ' + (diff * 3) + ' to ' +
    (++diff * 3) + ' months ago'
  );
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.24.0/moment.min.js"></script>
RobG
  • 124,520
  • 28
  • 153
  • 188
1

The modulo makes sense to me. If you roll your own dates, it works like this (plus or minus a leap-year-day, which is what libraries like moment.js are good at abstracting away):

const projects = [
  { id: 1, startDate: 1551441600000 },
  { id: 2, startDate: 1554120000000 },
  { id: 3, startDate: 1556712000000 },
  { id: 4, startDate: 1559390400000 },
  { id: 5, startDate: 1564660800000 }
];

// Gets current year, month, and date
const now = new Date(),
      thisYear = now.getFullYear(),
      thisMonth = now.getUTCMonth(),
      thisDate = now.getUTCDate();

// Loops through projects
projects.forEach(project => {

  // Gets year, month, and date for each project
   const then = new Date(project.startDate),
     startYear = then.getFullYear(),
     startMonth = then.getUTCMonth(),
     startDate = then.getUTCDate();
  //console.log(then.toUTCString());


  // Reports on the project if it started on an earlier day of the month 3, 6, etc months ago
  const justStarted = thisYear == startYear && thisMonth == startMonth,
        isQuarterInterval = thisMonth % 3 == startMonth % 3 && thisDate >= startDate
  if(isQuarterInterval && !justStarted){
    console.log("Project #" + project.id + " started " + then);
  }
});
Cat
  • 3,575
  • 2
  • 6
  • 15