Custom date range sorting

时间:2017-04-10 01:43:56

标签: javascript sorting typescript

I am going though a project an attempting to remove unnecessary 3rd party dependencies in places where native JS accomplishes the job. We use Underscore's _.sortBy to sort an array of dates, but for some reason I can't quite duplicate the exact sort order yet.

The data comes back unsorted and looks like this:

{
    "title": "February 2016",
    "startTime": "2016-02-01T10:00:00.000Z",
    "endTime": "2016-03-01T09:59:59.000Z"
  },
  {
    "title": "Week of February 28 2016",
    "startTime": "2016-02-28T05:00:00.000Z",
    "endTime": "2016-03-06T04:59:59.000Z"
  },
  {
    "title": "March 2016",
    "startTime": "2016-03-01T10:00:00.000Z",
    "endTime": "2016-04-01T07:59:59.000Z"
  },
  {
    "title": "Week of March 06 2016",
    "startTime": "2016-03-06T05:00:00.000Z",
    "endTime": "2016-03-13T04:59:59.000Z"
  },
  {
    "title": "Week of March 13 2016",
    "startTime": "2016-03-13T05:00:00.000Z",
    "endTime": "2016-03-20T03:59:59.000Z"
  },

Basically it needs just standard date sorting, except the "week of..." ranges should appear before the entire month range.

This is how it is done currently using Underscore & MomentJS (also using Typescript), this correctly sorts it exactly how we want:

_.sortBy(dateRanges, (range: IDateRange) => {
  if (moment(range.endTime).diff(range.startTime, "days") > 7) {
    return range.endTime;
  } else {
    return range.startTime;
  }
});

I am attempting to duplicate that exact output, but without using Underscore or MomentJS. Here's what I have so far:

dateRanges.sort((r1: IDateRange, r2: IDateRange) => {
  //604800000 milliseconds in 1 week
  //easier to hard code number this than do all the math on each iteration here
  const isWholeMonth = r1.endTime.getTime() - r1.startTime.getTime() > 604800000;

  if (isWholeMonth) {
    if (r1.endTime > r2.endTime) {
      return 1;
    } else if (r1.endTime < r2.endTime) {
      return -1;
    }
    return 0;
  } else {
    //Make the week listings for a month appear before the entire month listings
    if (r1.startTime > r2.startTime) {
      return 1;
    } else if (r1.startTime < r2.startTime) {
      return -1;
    }
    return 0;
  }
});

It's not entirely sorting correctly yet, but I can't quite figure out why. Here's a working demo that outputs both of those to the console so the
http://codepen.io/chrismbarr/pen/KWOaaE

1 个答案:

答案 0 :(得分:1)

Underscore's _sortBy works differently than native sort. You need to check and compare different things, depending on if you have the 'week' present in the title or not (or check startTime and endTime, up to you):

interface IDateRange {
    title: string;
    startTime: Date;
    endTime: Date;
}

const dateRanges: IDateRange[] = [
  {
    "title": "February 2016",
    "startTime": "2016-02-01T10:00:00.000Z",
    "endTime": "2016-03-01T09:59:59.000Z"
  },
  {
    "title": "Week of February 28 2016",
    "startTime": "2016-02-28T05:00:00.000Z",
    "endTime": "2016-03-06T04:59:59.000Z"
  },
  {
    "title": "March 2016",
    "startTime": "2016-03-01T10:00:00.000Z",
    "endTime": "2016-04-01T07:59:59.000Z"
  },
  {
    "title": "Week of March 06 2016",
    "startTime": "2016-03-06T05:00:00.000Z",
    "endTime": "2016-03-13T04:59:59.000Z"
  },
  {
    "title": "Week of March 13 2016",
    "startTime": "2016-03-13T05:00:00.000Z",
    "endTime": "2016-03-20T03:59:59.000Z"
  },
  {
    "title": "October 2016",
    "startTime": "2016-10-01T08:00:00.000Z",
    "endTime": "2016-11-01T07:59:59.000Z"
  },
  {
    "title": "Week of October 02 2016",
    "startTime": "2016-10-02T04:00:00.000Z",
    "endTime": "2016-10-09T03:59:59.000Z"
  },
  {
    "title": "Week of October 30 2016",
    "startTime": "2016-10-30T04:00:00.000Z",
    "endTime": "2016-11-06T03:59:59.000Z"
  },
  {
    "title": "November 2016",
    "startTime": "2016-11-01T08:00:00.000Z",
    "endTime": "2016-12-01T09:59:59.000Z"
  },
  {
    "title": "Week of November 13 2016",
    "startTime": "2016-11-13T05:00:00.000Z",
    "endTime": "2016-11-20T04:59:59.000Z"
  },
  {
    "title": "Week of November 20 2016",
    "startTime": "2016-11-20T05:00:00.000Z",
    "endTime": "2016-11-27T04:59:59.000Z"
  },
  {
    "title": "Week of November 27 2016",
    "startTime": "2016-11-27T05:00:00.000Z",
    "endTime": "2016-12-04T04:59:59.000Z"
  },
  {
    "title": "December 2016",
    "startTime": "2016-12-01T10:00:00.000Z",
    "endTime": "2017-01-01T09:59:59.000Z"
  },
  {
    "title": "Week of December 04 2016",
    "startTime": "2016-12-04T05:00:00.000Z",
    "endTime": "2016-12-11T04:59:59.000Z"
  },
  {
    "title": "Week of December 11 2016",
    "startTime": "2016-12-11T05:00:00.000Z",
    "endTime": "2016-12-18T04:59:59.000Z"
  },
  {
    "title": "Week of December 25 2016",
    "startTime": "2016-12-25T05:00:00.000Z",
    "endTime": "2017-01-01T04:59:59.000Z"
  },
  {
    "title": "January 2017",
    "startTime": "2017-01-01T10:00:00.000Z",
    "endTime": "2017-02-01T09:59:59.000Z"
  },
  {
    "title": "Week of January 15 2017",
    "startTime": "2017-01-15T05:00:00.000Z",
    "endTime": "2017-01-22T04:59:59.000Z"
  },
  {
    "title": "Week of January 29 2017",
    "startTime": "2017-01-29T05:00:00.000Z",
    "endTime": "2017-02-05T04:59:59.000Z"
  },
  {
    "title": "February 2017",
    "startTime": "2017-02-01T10:00:00.000Z",
    "endTime": "2017-03-01T09:59:59.000Z"
  },
  {
    "title": "Week of February 05 2017",
    "startTime": "2017-02-05T05:00:00.000Z",
    "endTime": "2017-02-12T04:59:59.000Z"
  },
  {
    "title": "Week of February 12 2017",
    "startTime": "2017-02-12T05:00:00.000Z",
    "endTime": "2017-02-19T04:59:59.000Z"
  },
  {
    "title": "March 2017",
    "startTime": "2017-03-01T10:00:00.000Z",
    "endTime": "2017-04-01T07:59:59.000Z"
  },
  {
    "title": "Week of March 05 2017",
    "startTime": "2017-03-05T05:00:00.000Z",
    "endTime": "2017-03-12T04:59:59.000Z"
  },
  {
    "title": "Week of March 12 2017",
    "startTime": "2017-03-12T05:00:00.000Z",
    "endTime": "2017-03-19T03:59:59.000Z"
  },
  {
    "title": "Week of March 19 2017",
    "startTime": "2017-03-19T04:00:00.000Z",
    "endTime": "2017-03-26T03:59:59.000Z"
  },
  {
    "title": "Week of March 26 2017",
    "startTime": "2017-03-26T04:00:00.000Z",
    "endTime": "2017-04-02T03:59:59.000Z"
  }
];

////==============================

console.clear();

//Convert to real data objects...
for (const range of dateRanges) {
  range.startTime = moment(range.startTime).utc().toDate();
  range.endTime = moment(range.endTime).utc().toDate();
}


//OLD
const librarySort = _.sortBy(dateRanges, (range: IDateRange) => {
  if (moment(range.endTime).diff(range.startTime, "days") > 7) {
    return range.endTime;
  } else {
    return range.startTime;
  }
});

//NEW - changes made here
const nativeSort = dateRanges.sort((r1: IDateRange, r2: IDateRange) => {
  let firstPartToCompare;
  let secondPartToCompare;

  if(r1.title.indexOf('eek') > -1) {
    firstPartToCompare = r1.startTime;
  } else {
    firstPartToCompare = r1.endTime;
  }

  if(r2.title.indexOf('eek') > -1) {
    secondPartToCompare = r2.startTime;
  } else {
    secondPartToCompare = r2.endTime;
  }

  if (firstPartToCompare > secondPartToCompare) {
    return 1;
  } else if (firstPartToCompare < secondPartToCompare) {
    return -1;
  }
  return 0;
});

console.info("CORRECT order - old way")
console.table(librarySort);

console.info("ATTEMPT to duplicate - new way")
console.table(nativeSort);

http://codepen.io/anon/pen/GWVrwB