按日期排序对象数组的问题& Javascript中的时间 - 允许空值

时间:2010-07-31 22:55:39

标签: javascript arrays sorting null date

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

地方

  • 标题
  • 日期(可选)
  • 时间(可选)

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

目前,它在浏览器中的表现不同。这是代码(假设我在_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);
}

如果您认识到上面的排序代码,那是因为我从另一篇文章中得到了基础知识,但我觉得这个应该是自己的,因为它处理日期......另一个只是处理空值和文本。

无论如何,在Chrome中,列表似乎按随机顺序排序,并且每次执行_orderByDate函数时它都会保持不同的排序。在Safari中,它首次排序大部分是正确的,但是在列表的顶部放置一个空日期。在Firefox中,根本没有任何事情发生。

我是一个初学者,我根本没有CS背景,所以我不擅长数组,日期,时间等基础...我的调试技巧仅限于Firebug控制台。没有错误报告,所以我真的不知道出了什么问题。

有一点需要注意,如果我从函数中删除日期类型,以便将项目排序为字符串,它可以正常工作......但这意味着1/10/2011将在2011年9月1日之前排序,所以我我觉得我需要那里的日期类型。

任何想法出了什么问题?有没有更聪明的方法来做我想做的事情?

编辑:添加日志值

首先排序(Chrome):

  • 08/01/2010
  • null
  • null
  • 08/03/2010
  • 2010年7月1日

第二种排序(Chrome):

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

3 个答案:

答案 0 :(得分:3)

<强> [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);
});

答案 1 :(得分:3)

如果您预先处理数组,那么您可以大大简化排序算法,使其具有您要排序的列的数字表示。

在表中添加一列,其中包含例如日期的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;
});

如果您不想使用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;
});

当然,这假设您的日期始终具有相同的M / D / Y格式。

以上是上面的算法:http://jsfiddle.net/krNnn/

答案 2 :(得分:0)

好的,我们忙着构建一个相当复杂的功能,适用于所有浏览器。我们的一些要求非常特殊(在遥远的过去的日期,需要在底部对空日期进行排序,按时间分类)。这就是我们所做的:

         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);
        }