1

Given the following array:

var effectiveDates= [
    {
        actualDate: "2017-08-29",
        effectiveDate: "2017-01-01",
        time: "13:22"
    },
    {
        actualDate: "2017-08-29",
        effectiveDate: "2017-01-01",
        time: "11:33"
    },
    {
        actualDate: "2017-08-29",
        effectiveDate: "2017-01-01",
        time: "10:57"
    },
    {
        actualDate: "2016-06-17",
        effectiveDate: "2016-01-01",
        time: "10:26"
    },
    {
        actualDate: "2016-06-17",
        effectiveDate: "2016-01-01",
        time: "10:03"
    },
    {
        actualDate: "2015-12-03",
        effectiveDate: "2015-01-01",
        time: "16:54"
    },
    {
        actualDate: "2014-07-07",
        effectiveDate: "2014-05-01",
        time: "10:47"
    },
    {
        actualDate: "2014-07-07",
        effectiveDate: "2014-05-01",
        time: "10:41"
    },
    {
        actualDate: "2014-07-07",
        effectiveDate: "2014-01-01",
        time: "10:36"
    },
    {
        actualDate: "2014-07-07",
        effectiveDate: "2014-01-01",
        time: "10:36"
    }
]

I am trying to sort the data based on actualDate or effectiveDate descending (or ascending depending on the order) and then by the time (also ascending or descending based on the required order). The issue I am having is that the dates order correct, but the time property does not order correctly. I am using moment.js for the date and time parsing.

This is what I have attempted so far:

var desc = true; //false;
effectiveDates.sort(function (a, b) {
            if (desc) {
                if (moment(a.actualDate) === moment(b.actualDate)) {
                    return (moment(b.time) - moment(a.time));
                } else if (moment(a.actualDate) < moment(b.actualDate)) {
                    return 1;
                } else if (moment(a.actualDate) > moment(b.actualDate)) {
                    return -1;
                }
            }
            else {
                if (moment(a.actualDate) === moment(b.actualDate)) {
                    return (moment(b.time) - moment(a.time));
                } else if (moment(a.actualDate) > moment(b.actualDate)) {
                    return 1;
                } else if (moment(a.actualDate) < moment(b.actualDate)) {
                    return -1;
                }
            }
        });

For some reason, when ordering the data by effectiveDate ascending or descending, the time is ordered correctly. But when ordering the data by actualDate, also ascending or descending, the time data is incorrect.

Any help would be greatly appreciated.

3
  • Instead of calling moment(a.actualDate) a load of times, better store them in a variable: aDate = moment(a.actualDate) etc. Commented Sep 1, 2017 at 15:03
  • 1
    Your time comparisons are made in the same direction in both cases. Commented Sep 1, 2017 at 15:12
  • There is also no need to for the else.... you can just have one set and flip the -1 or 1 based on desc. Commented Sep 1, 2017 at 15:22

2 Answers 2

2

Instead of

return (moment(b.time) - moment(a.time));

Use:

moment(a.time, "HH:mm") - moment(b.time, "HH:mm")

You need to tell moment.js that the input strings are "time" strings.

Sign up to request clarification or add additional context in comments.

Comments

1

Three issues:

  1. Using === to compare two moments won't work; they'll never be equal. Moment provides a .isSame function to do this.
  2. To parse the times, you need to provide a format string, in this case "HH:mm".
  3. The subtraction of the two times needs to reverse between ascending and descending. Just flip the order.

See a working version below, with comments indicating the changes:

function sorted(desc) {
    return effectiveDates.sort(function (a, b) {
        if (desc) {
            // Use .isSame to compare two moments:
            if (moment(a.actualDate).isSame(moment(b.actualDate))) {
                // Provide a format to moment so it knows how to parse the times:
                return moment(b.time, "HH:mm") - moment(a.time, "HH:mm");
            } else if (moment(a.actualDate) < moment(b.actualDate)) {
                return 1;
            } else if (moment(a.actualDate) > moment(b.actualDate)) {
                return -1;
            }
        }
        else {
            if (moment(a.actualDate).isSame(moment(b.actualDate))) {
                // Reverse the order of the subtraction when sorting ascending:
                return moment(a.time, "HH:mm") - moment(b.time, "HH:mm");
            } else if (moment(a.actualDate) > moment(b.actualDate)) {
                return 1;
            } else if (moment(a.actualDate) < moment(b.actualDate)) {
                return -1;
            }
        }
    });
}

Output of these calls,

console.log("DESCENDING:");
console.log(sorted(true));

console.log("ASCENDING:");
console.log(sorted(false));

is:

DESCENDING:
[ { actualDate: '2017-08-29',
    effectiveDate: '2017-01-01',
    time: '13:22' },
  { actualDate: '2017-08-29',
    effectiveDate: '2017-01-01',
    time: '11:33' },
  { actualDate: '2017-08-29',
    effectiveDate: '2017-01-01',
    time: '10:57' },
  { actualDate: '2016-06-17',
    effectiveDate: '2016-01-01',
    time: '10:26' },
  { actualDate: '2016-06-17',
    effectiveDate: '2016-01-01',
    time: '10:03' },
  { actualDate: '2015-12-03',
    effectiveDate: '2015-01-01',
    time: '16:54' },
  { actualDate: '2014-07-07',
    effectiveDate: '2014-05-01',
    time: '10:47' },
  { actualDate: '2014-07-07',
    effectiveDate: '2014-05-01',
    time: '10:41' },
  { actualDate: '2014-07-07',
    effectiveDate: '2014-01-01',
    time: '10:36' },
  { actualDate: '2014-07-07',
    effectiveDate: '2014-01-01',
    time: '10:36' } ]
ASCENDING:
[ { actualDate: '2014-07-07',
    effectiveDate: '2014-01-01',
    time: '10:36' },
  { actualDate: '2014-07-07',
    effectiveDate: '2014-01-01',
    time: '10:36' },
  { actualDate: '2014-07-07',
    effectiveDate: '2014-05-01',
    time: '10:41' },
  { actualDate: '2014-07-07',
    effectiveDate: '2014-05-01',
    time: '10:47' },
  { actualDate: '2015-12-03',
    effectiveDate: '2015-01-01',
    time: '16:54' },
  { actualDate: '2016-06-17',
    effectiveDate: '2016-01-01',
    time: '10:03' },
  { actualDate: '2016-06-17',
    effectiveDate: '2016-01-01',
    time: '10:26' },
  { actualDate: '2017-08-29',
    effectiveDate: '2017-01-01',
    time: '10:57' },
  { actualDate: '2017-08-29',
    effectiveDate: '2017-01-01',
    time: '11:33' },
  { actualDate: '2017-08-29',
    effectiveDate: '2017-01-01',
    time: '13:22' } ]

UPDATE

A simpler comparator function:

function sorted(desc) {
    return effectiveDates.sort(function (a, b) {
        // Combine the date and time and parse them together.
        var ret = moment(a.actualDate + " " + a.time) - moment(b.actualDate + " " + b.time);

        // Flip the sign if we're sorting descending.
        if (desc) {
            ret *= -1;
        }

        return ret;
    });
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.