根据Javascript中的日期和时间对对象数组进行排序的问题——空值允许

时间:2022-09-25 12:40:30

I'm working with an array of objects in Javascript and need to sort them by date and time. Here's the setup:

我正在使用Javascript中的对象数组,需要按日期和时间对它们进行排序。这是设置:

place

的地方

  • title
  • 标题
  • date (optional)
  • 日期(可选)
  • time (optional)
  • 时间(可选)

Conceptually, the application allows users to create a list of places they're planning to go. The array of events is manually ordered at first, and users can optionally add date and time values to places. I'm providing an button to sort by date...places with null dates need to be placed at the bottom of the list.

从概念上讲,应用程序允许用户创建他们计划要去的地方的列表。事件数组首先是手动排序的,用户可以选择向位置添加日期和时间值。我提供了一个按日期排序的按钮……需要将具有空日期的位置放在列表的底部。

Right now, it's behaving differently across browsers. Here's the code (assume I have a handle on the _places array and the _list object):

现在,它在不同的浏览器中表现不同。下面是代码(假设我在_places数组和_list对象上有一个句柄):

var _orderByDate = function (e) {
    YUE.preventDefault(e); // yui
    _places.sort(function (a, b) {
        var dateA = new Date(a.date),
            dateB = new Date(b.date);
        if ((!dateA === null) && (dateB === null)) return 0; //they're both null and equal
        else if ((dateA === null) && (dateB != null)) return -1; //move a downwards
        else if ((dateA != null) && (dateB === null)) return 1; //move b downwards
        else if ((dateA == dateB)) return (a.time > b.time) ? 1 : ((b.time > a.time) ? -1 : 0);
        else return (dateA > dateB) ? 1 : ((dateB > dateA) ? -1 : 0);
    });
    _list.updatePlaces(_places);
}

If you recognize the sort code above, that's because I got the basics from another post, but I felt this one deserved it's own since it deals with dates...the other was just dealing with null values and text.

如果您认识上面的排序代码,那是因为我从另一篇文章中获得了基本的信息,但是我觉得这篇文章值得拥有,因为它涉及日期……另一个只是处理空值和文本。

Anyway, in Chrome, the list seems to sort in a random order, and it keeps sorting differently every time I execute the _orderByDate function. In Safari, it sorts mostly correct the first time, but puts one null date place at the top of the list. In Firefox, nothing happens at all.

无论如何,在Chrome中,列表的排序顺序似乎是随机的,而且每次执行_orderByDate函数时,列表的排序方式都是不同的。在Safari中,它第一次排序时基本都是正确的,但是在列表的最前面放一个空日期位置。在Firefox中,什么都没有发生。

I'm a bit of a beginner, and I don't have a CS background at all, so I'm not adept at the basics like arrays, dates, times etc...and my debugging skills are limited to the Firebug console. No errors are being reported, so I really have no idea what's going wrong.

我是一个初学者,我完全没有CS背景,所以我不擅长像数组、日期、时间等基础知识。我的调试技能仅限于Firebug控制台。没有错误报告,所以我真的不知道哪里出错了。

One thing to note, if I eliminate the date type from the function so it sorts the items as strings, it works correctly...but that means 1/10/2011 would sort before 1/9/2011, so I think I need the date type in there.

需要注意的是,如果我从函数中删除日期类型,以便它将项排序为字符串,那么它就可以正常工作……但这意味着1/10/2011会在1/9/2011之前排序,所以我需要这里的日期类型。

Any ideas what's going wrong? Is there a smarter way to do what I'm trying to do?

有什么问题吗?有没有更聪明的方法去做我想做的事?

EDIT: Adding log values

编辑:添加日志值

First sort (Chrome):

  • 08/01/2010
  • 08/01/2010
  • null
  • null
  • 08/03/2010
  • 08/03/2010
  • null
  • null
  • null
  • null
  • 7/01/2010
  • 7/01/2010
  • null
  • null
  • null

Second sort (Chrome):

  • 08/01/2010
  • 08/01/2010
  • null
  • null
  • null
  • 07/01/2010
  • 07/01/2010
  • null
  • null
  • null
  • null
  • null
  • 8/03/2010
  • 8/03/2010
  • null
  • null

3 个解决方案

#1


3  

You can simplify the sorting algorithm by a great deal if you pre-process your array so that it will have a numeric representation of the column you want to sort by.

如果对数组进行预处理,就可以大大简化排序算法,使其具有要排序的列的数字表示形式。

Add a column to the table that contains the UTC equivalent of the dates for instance. Then you can safely sort the array by the UTC property, but you will still display the string value.

将一个列添加到表中,该列包含实例的UTC值。然后可以通过UTC属性安全地对数组进行排序,但是仍然会显示字符串值。

for (var idx in _places)
    _places[idx].UTC = _places[idx].date ? new Date(_places[idx].date).UTC() : 0;

_places.sort(function(a, b)
{
    return a.UTC > b.UTC ? 1 : a.UTC < b.UTC ? -1 : 0;
});

If you don't want to use the Date object (pre-1970 dates):

如果您不想使用Date对象(1970年以前的日期):

for (var idx in _places)
{
    var row = _places[idx];
    if (!row.date)
    {
        row.sortable = 0;
        continue;
    }
    var date = row.date.split('/');
    row.sortable = 10000 * parseInt(date[2]) + 100 * parseInt(date[0]) + parseInt(date[1]); // year, month, day
}

_places.sort(function(a, b)
{
    return a.sortable > b.sortable ? 1 : a.sortable < b.sortable ? -1 : 0;
});

Of course this assumes that your dates will always have the same M/D/Y format.

当然,这假定您的约会将始终具有相同的M/D/Y格式。

Here's the above algorithm in action: http://jsfiddle.net/krNnn/

下面是上述算法的作用:http://jsfiddle.net/krNnn/。

#2


2  

[See it in action]

(在行动)

_places.sort(function (a, b) {
    var dateA = new Date(a.date + a.time), // merge the date & time
        dateB = new Date(b.date + b.time); // depending on the format
    if (!a.date && b.date) return 1;
    else if (a.date && !b.date) return -1;
    else if (dateA === dateB) return 0;
    else return (dateA > dateB) ? 1 : (dateB > dateA ? -1 : 0);
});

#3


0  

Ok, we got busy and built a rather complex function that works across all browsers. Some of the requirements we had were pretty special (dates in the distant past, need to sort null dates at the bottom, subsort by time). Here's what we did:

好了,我们忙了起来,构建了一个相当复杂的函数,可以在所有浏览器上运行。我们的一些需求是非常特殊的(日期在遥远的过去,需要排序底部的空日期,按时间进行子排序)。这是我们所做的:

         var _orderByDate = function(e) {
            YUE.preventDefault(e);
            _places.sort(function(a,b) {

                var Ay, Am, Ad, By, Bm, Bd;
                var Ah, Am, Bh, Bm;

                var dateA = a.date.split("/"); 
                if( !dateA.length || dateA.length != 3 || isNaN(dateA[0]) ||
                    isNaN(dateA[1]) || isNaN(dateA[2]) ) {
                    dateA = -1;
                } else {
                    Ay = parseInt(dateA[2]);
                    Am = parseInt(dateA[0]);
                    Ad = parseInt(dateA[1]);
                }

                var dateB = b.date.split("/"); 
                if( !dateB.length || dateB.length != 3 || isNaN(dateB[0]) || 
                    isNaN(dateB[1]) || isNaN(dateB[2]) ) {
                    dateB = -1;
                } else {
                    By = parseInt(dateB[2]);
                    Bm = parseInt(dateB[0]);
                    Bd = parseInt(dateB[1]);
                }

                // null checks
                if(dateA == -1 && dateB == -1) return 0;
                if(dateA == -1 && dateB != -1) return 1;
                if(dateA != -1 && dateB == -1) return -1;

                // year check
                if(Ay > By) return  1;
                if(By > Ay) return -1;

                // month check
                if(Am > Bm) return  1;
                if(Bm > Am) return -1;

                // day check
                if(Ad > Bd) return  1;
                if(Bd > Ad) return -1;


                var timeA = a.time.split(":");
                if( !timeA.length || timeA.length != 2 || isNaN(timeA[0]) ) {
                    timeA = -1;
                } else {
                    if( timeA[1].match(/am/) ) {
                        Ah = parseInt(timeA[0]);
                        Am = parseInt(timeA[1].match(/\d+/));
                    } else if( timeA[1].match(/pm/) ) {
                        Ah = parseInt((timeA[0] * 1) + 12);
                        Am = parseInt(timeA[1].match(/\d+/));
                    }
                }
                var timeB = b.time.split(":");
                if( !timeB.length || timeB.length != 2 || isNaN(timeB[0]) ) {
                    timeB = -1;
                } else {
                    if( timeB[1].match(/am/) ) {
                        Bh = parseInt(timeB[0]);
                        Bm = parseInt(timeB[1].match(/\d+/));
                    } else if( timeB[1].match(/pm/) ) {
                        Bh = parseInt((timeB[0] * 1) + 12);
                        Bm = parseInt(timeB[1].match(/\d+/));
                    }
                }

                // null time checks
                if(timeA == -1 && timeB == -1) return 0;
                if(timeA == -1 && timeB != -1) return 1;
                if(timeA != -1 && timeB == -1) return -1;

                // hour check
                if(Ah > Bh) return  1;
                if(Bh > Ah) return -1;

                // minute check
                if(Am > Bm) return  1;
                if(Bm > Am) return -1;

                return 0;
            } );

            _list.updatePlaces(_places);
        }

#1


3  

You can simplify the sorting algorithm by a great deal if you pre-process your array so that it will have a numeric representation of the column you want to sort by.

如果对数组进行预处理,就可以大大简化排序算法,使其具有要排序的列的数字表示形式。

Add a column to the table that contains the UTC equivalent of the dates for instance. Then you can safely sort the array by the UTC property, but you will still display the string value.

将一个列添加到表中,该列包含实例的UTC值。然后可以通过UTC属性安全地对数组进行排序,但是仍然会显示字符串值。

for (var idx in _places)
    _places[idx].UTC = _places[idx].date ? new Date(_places[idx].date).UTC() : 0;

_places.sort(function(a, b)
{
    return a.UTC > b.UTC ? 1 : a.UTC < b.UTC ? -1 : 0;
});

If you don't want to use the Date object (pre-1970 dates):

如果您不想使用Date对象(1970年以前的日期):

for (var idx in _places)
{
    var row = _places[idx];
    if (!row.date)
    {
        row.sortable = 0;
        continue;
    }
    var date = row.date.split('/');
    row.sortable = 10000 * parseInt(date[2]) + 100 * parseInt(date[0]) + parseInt(date[1]); // year, month, day
}

_places.sort(function(a, b)
{
    return a.sortable > b.sortable ? 1 : a.sortable < b.sortable ? -1 : 0;
});

Of course this assumes that your dates will always have the same M/D/Y format.

当然,这假定您的约会将始终具有相同的M/D/Y格式。

Here's the above algorithm in action: http://jsfiddle.net/krNnn/

下面是上述算法的作用:http://jsfiddle.net/krNnn/。

#2


2  

[See it in action]

(在行动)

_places.sort(function (a, b) {
    var dateA = new Date(a.date + a.time), // merge the date & time
        dateB = new Date(b.date + b.time); // depending on the format
    if (!a.date && b.date) return 1;
    else if (a.date && !b.date) return -1;
    else if (dateA === dateB) return 0;
    else return (dateA > dateB) ? 1 : (dateB > dateA ? -1 : 0);
});

#3


0  

Ok, we got busy and built a rather complex function that works across all browsers. Some of the requirements we had were pretty special (dates in the distant past, need to sort null dates at the bottom, subsort by time). Here's what we did:

好了,我们忙了起来,构建了一个相当复杂的函数,可以在所有浏览器上运行。我们的一些需求是非常特殊的(日期在遥远的过去,需要排序底部的空日期,按时间进行子排序)。这是我们所做的:

         var _orderByDate = function(e) {
            YUE.preventDefault(e);
            _places.sort(function(a,b) {

                var Ay, Am, Ad, By, Bm, Bd;
                var Ah, Am, Bh, Bm;

                var dateA = a.date.split("/"); 
                if( !dateA.length || dateA.length != 3 || isNaN(dateA[0]) ||
                    isNaN(dateA[1]) || isNaN(dateA[2]) ) {
                    dateA = -1;
                } else {
                    Ay = parseInt(dateA[2]);
                    Am = parseInt(dateA[0]);
                    Ad = parseInt(dateA[1]);
                }

                var dateB = b.date.split("/"); 
                if( !dateB.length || dateB.length != 3 || isNaN(dateB[0]) || 
                    isNaN(dateB[1]) || isNaN(dateB[2]) ) {
                    dateB = -1;
                } else {
                    By = parseInt(dateB[2]);
                    Bm = parseInt(dateB[0]);
                    Bd = parseInt(dateB[1]);
                }

                // null checks
                if(dateA == -1 && dateB == -1) return 0;
                if(dateA == -1 && dateB != -1) return 1;
                if(dateA != -1 && dateB == -1) return -1;

                // year check
                if(Ay > By) return  1;
                if(By > Ay) return -1;

                // month check
                if(Am > Bm) return  1;
                if(Bm > Am) return -1;

                // day check
                if(Ad > Bd) return  1;
                if(Bd > Ad) return -1;


                var timeA = a.time.split(":");
                if( !timeA.length || timeA.length != 2 || isNaN(timeA[0]) ) {
                    timeA = -1;
                } else {
                    if( timeA[1].match(/am/) ) {
                        Ah = parseInt(timeA[0]);
                        Am = parseInt(timeA[1].match(/\d+/));
                    } else if( timeA[1].match(/pm/) ) {
                        Ah = parseInt((timeA[0] * 1) + 12);
                        Am = parseInt(timeA[1].match(/\d+/));
                    }
                }
                var timeB = b.time.split(":");
                if( !timeB.length || timeB.length != 2 || isNaN(timeB[0]) ) {
                    timeB = -1;
                } else {
                    if( timeB[1].match(/am/) ) {
                        Bh = parseInt(timeB[0]);
                        Bm = parseInt(timeB[1].match(/\d+/));
                    } else if( timeB[1].match(/pm/) ) {
                        Bh = parseInt((timeB[0] * 1) + 12);
                        Bm = parseInt(timeB[1].match(/\d+/));
                    }
                }

                // null time checks
                if(timeA == -1 && timeB == -1) return 0;
                if(timeA == -1 && timeB != -1) return 1;
                if(timeA != -1 && timeB == -1) return -1;

                // hour check
                if(Ah > Bh) return  1;
                if(Bh > Ah) return -1;

                // minute check
                if(Am > Bm) return  1;
                if(Bm > Am) return -1;

                return 0;
            } );

            _list.updatePlaces(_places);
        }