简体   繁体   中英

How to sort javascript array with multiple datetime columns

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.

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.

Three issues:

  1. Using === to compare two moment s 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;
    });
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM