2

The goal is to use Javascript to UNIQUELY calculate the total years of a person's work experience, from an array of Date Ranges of the person's work history. There are Date Ranges which overlap (meaning, the person had multiple jobs within the overlapping period). Here is an example below and the date format is yyyy-mm-dd;

  • 2001-02-01 to 2009-03-01
  • 2004-06-01 to 2020-08-01
  • 2005-04-01 to 2021-03-01
  • 2008-07-01 to 2016-06-01

From the date ranges above, there are overlapping work dates. The correct computation of the person's years of work experience should be 20 years.

The problem I have is to creating an algorithm that can put into account, the overlapping periods within the person's four work histories and not count them as separate years of work experience E.g just summing up the years between each of the four job dates gives 48 years WHICH IS INCORRECT (The experience was over a 20-year period).

var time_diff=0, yrs_diff=0;

var jobExperience = [
  {date_began:'2001-02-01', date_ended:'2009-03-01'},
  {date_began:'2004-06-01', date_ended:'2020-08-01'},
  {date_began:'2005-04-01', date_ended:'2021-03-01'},
  {date_began:'2008-07-01', date_ended:'2016-06-01'}
];
for(let i=0; i<jobExperience.length; i++){
  let date_1, date_2;
  let began = jobExperience[i].date_began.split('-');
  let ended = jobExperience[i].date_ended.split('-');
  date_1 = new Date(began[1]+'/'+began[2]+'/'+began[0]);
  date_2 = new Date(ended[1]+'/'+ended[2]+'/'+ended[0]);
  time_diff += date_2.getTime() - date_1.getTime();
}
yrs_diff = parseInt(time_diff/(1000 * 3600 * 24 * 365));
console.log(yrs_diff);

The snippet above only just blindly adds up the years between each record of work history (This is not correct). Where I need some help is a clue or better still pseudocode or complete code on how to sum up the years between each record of work history but account for overlaps between work history dates and by so doing, overlapping periods are only counted once.

AbsoluteBeginner
  • 2,160
  • 3
  • 11
  • 21
Chouchou
  • 23
  • 5
  • 3
    what did you try so far? show code example with your data – Omri Attiya Apr 30 '21 at 07:08
  • One way is to check every period against every other period for overlap. If one of them contains the other entirely, remove the smaller one from the pool. Then start over, and look for partial overlap. If one is found, remove it from one of the periods (say always the first one). After that, there shouldn't be any overlap left, so now all you have to do is sum up the remaining periods. –  Apr 30 '21 at 07:18
  • A second approach is to split all periods based on another period's start or end date that lies inside it. For instance the first one becomes 2001-02-01 to 2004-06-01, 2004-06-01 to 2009-03-01 as a first step due to the start date of the second one. Once you've done that for all, you put them all in one big array and remove all duplicates. –  Apr 30 '21 at 07:22
  • A third approach is to create a list of all months, based on the earliest and the latest date. Then let each period mark all its months, then finally count all marked months. –  Apr 30 '21 at 07:24
  • Calculate the [union of intervals](https://stackoverflow.com/a/1034833/240443); this will reduce your list to non-overlapping intervals. Then simply add their durations as you did in your code. – Amadan Apr 30 '21 at 07:33

2 Answers2

2

Here's the approach I've outlined in my comment:

For each period, turn the start and end date into a unique "month value", then add all month values of a period to a set.
The size of the set is the wanted number of months:

const jobExperience = [
  { date_began: '2001-02-01', date_ended: '2009-03-01' },
  { date_began: '2004-06-01', date_ended: '2020-08-01' },
  { date_began: '2005-04-01', date_ended: '2021-03-01' },
  { date_began: '2008-07-01', date_ended: '2016-06-01' }
];

const months = new Set();

// convert date into unique integer month value based on year 1900
function m1900(yyyymmdd) {
  const [_, y, m, d] = yyyymmdd.match(/^(\d{4})-(\d{2})-(\d{2})$/).map(Number);
  return (y - 1900) * 12 + m;
}

jobExperience.forEach(job => {
  const m1 = m1900(job.date_began);
  const m2 = m1900(job.date_ended);
  for (let m = m1; m < m2; m++) months.add(m);
});
console.log("years:", months.size / 12);
  • Thanks Chris G. I was already trying out your first approach when I saw your answer. The first approach your provided me also looks great: "One way is to check every period against every other period for overlap. If one of them contains the other entirely, remove the smaller one from the pool. Then start over, and look for partial overlap. If one is found, remove it from one of the periods (say always the first one)." – Chouchou Apr 30 '21 at 07:53
  • Yeah, that first approach is probably more feasible if the resolution is higher. Btw, if you have a working solution, feel free to post it as answer! :) –  Apr 30 '21 at 09:30
0

Here is a "Brute Force" approach.

  • Extract all the unique years
  • Sort them
  • Find the difference between the latest to the oldest year

(Assuming that all the years in the dataset belong to a single field; Different fields should not be part of the same dataset)

Eg: [2001, 2004, 2005, 2008, 2009, 2016, 2020, 2021] => Working for 20 years.

A caveat with this method is that it fails to account for the months.

A solution to the same would be [NOT SURE] to convert the months to a year (month/12) and adding the same to the preceding year (Like Feb 2001 => 2001.166).

Another caveat is that it fails to account for any break taken in between. (As Pointed out in the Comments).

SNikhill
  • 446
  • 2
  • 8
  • This assumes no downtime though; if the person didn't work for a year at all, your approach will not detect that. –  Apr 30 '21 at 07:23
  • Ahh Yes, I just realised the same: What if the dataset is not continuous. – SNikhill Apr 30 '21 at 07:24