Как сортировать данные json сначала по данным, а затем по времени?



У меня есть данные json, подобные приведенным ниже. Я пытаюсь отсортировать его, используя приведенный ниже код



function comp(a, b) {

return new Date(a.event_date) - new Date(b.event_date);
}

data=data.sort(comp)


Но проблема в том, что два события могут быть в одни и те же даты, но в разное время, что является еще одним элементом в данных json под названием event_time, как можно видеть на тех же данных json.

Как отсортировать так, чтобы сначала он сортировал по event_date, а если они равны, то сортировал по их соответствующим временам ?



Заранее спасибо?



{
id: "xxxx",
feed_id: "yyyy",
title: "abcd ",
detail: "efgh.",
event_date: "Tue, 26 May 2015 00:00:00 +1000",
event_time: "6:30pm",
date: "Thu, 23 Apr 2015 23:05:04 +1000",
expires_at: 1432634400,
end_time: "8:00pm",
timestamp: 1429794304
},
{
id: "xxxx",
feed_id: "yyyy",
title: "efgh",
detail: "efgh.",
event_date: "Tue, 26 May 2015 00:00:00 +1000",
event_time: "4:30pm",
date: "Thu, 23 Apr 2015 23:05:04 +1000",
expires_at: 1432634400,
end_time: "8:00pm",
timestamp: 1429794304
}, {
id: "xxxx",
feed_id: "yyyy",
title: "ijkl",
detail: "efgh.",
event_date: "Tue, 27 May 2015 00:00:00 +1000",
event_time: "1:30pm",
date: "Thu, 23 Apr 2015 23:05:04 +1000",
expires_at: 1432634400,
end_time: "8:00pm",
timestamp: 1429794304
}
473   6  

6 ответов:

Если вычитание двух дат приводит к 0 (без разницы), включите время в уравнение. Что-то вроде:

var result = document.querySelector('#result');
result.textContent = 
   JSON.stringify(getData().sort(sortDateTime), null, ' ') +
   '\n\n**using sortDateTime2\n'+
   JSON.stringify(getData().sort(sortDateTime2), null, ' ');



function sortDateTime(a, b) {
  var A = new Date(a.event_date);
  var B = new Date(b.event_date);
  if (A - B == 0) {
    // no difference, include event_time
    var tA = a.event_time.split(':');
    var tB = b.event_time.split(':');
    A.setHours( /pm/i.test(tA[1]) ? +tA[0]+12 : tA[0] );
    A.setMinutes(+tA[1].replace(/[a-z]/gi, ''));
    B.setHours(/pm/i.test(tB[1]) ? +tB[0]+12 : tB[0]);
    B.setMinutes(+tB[1].replace(/[a-z]/gi, ''));
  }
  return A - B;
}

// sorting on date/time using setTime helper
function sortDateTime2(a, b) {
  return setTime(new Date(a.event_date), a.event_time) - 
         setTime(new Date(b.event_date), b.event_time);
}

// bonus: helper to set time from a time string
function setTime(thisDate, timeStr) {
  return new Date(
           [ [ thisDate.getFullYear(), 
               thisDate.getMonth()+1, 
               thisDate.getDate() 
             ].join('/'),
             timeStr.replace(/(a|p)/, function (m) {return ' ' + m;} ) ]
             .join(' ')
  );
}

function getData() {
  return [{
     id: "xxxx",
     feed_id: "yyyy",
     title: "abcd ",
     detail: "efgh.",
     event_date: "Tue, 26 May 2015 00:00:00 +1000",
     event_time: "6:30pm",
     date: "Thu, 23 Apr 2015 23:05:04 +1000",
     expires_at: 1432634400,
     end_time: "8:00pm",
     timestamp: 1429794304
    },
    {
     id: "xxxx",
     feed_id: "yyyy",
     title: "abcd ",
     detail: "efgh.",
     event_date: "Tue, 26 May 2015 00:00:00 +1000",
     event_time: "4:30pm",
     date: "Thu, 23 Apr 2015 23:05:04 +1000",
     expires_at: 1432634400,
     end_time: "8:00pm",
     timestamp: 1429794304
    },    {
     id: "xxxx",
     feed_id: "yyyy",
     title: "abcd ",
     detail: "efgh.",
     event_date: "Tue, 27 May 2015 00:00:00 +1000",
     event_time: "1:30pm",
     date: "Thu, 23 Apr 2015 23:05:04 +1000",
     expires_at: 1432634400,
     end_time: "8:00pm",
     timestamp: 1429794304
    }
  ];
}
<pre id="result"></pre>

Вот простое решение:

function comp(a, b) {
  var d1= new Date(a.event_date)*1,
      d2= new Date(b.event_date)*1,
      t1= new Date('1/1/1970 '+(a.event_time.replace(/(a|p)/i, ' $1')))*1,
      t2= new Date('1/1/1970 '+(b.event_time.replace(/(a|p)/i, ' $1')))*1;

  return (d1+t1)-(d2+t2);
} //comp

Этот код:

  1. вставляет пробел перед "pm "или" am", чтобы сделать время действительным.
  2. добавляет каждый раз к дате 1/1/1970 и преобразует ее в дату.
  3. делает все даты числовыми (число миллисекунд с 1/1/1970).
  4. вычитает сумму b. event_date и b. event_time (в виде даты) из суммы a.event_date и A.event_time (в виде даты).

Он работает независимо от случая "pm" или " am", или количество пробелов (0 или более) перед "pm "или" am."Если "ПМ" или " ам " отсутствуют, это предполагает 24-часовое военное время.

Скрипка

Я не думаю, что Date.parse работает для вашего формата времени. Вы можете использовать что-то вроде этого:

function parseDateTime(d, t) {
  var date = new Date(d);
  var a = t.slice(-2);
  var t = +t.replace(/[apm:]/g, '');
  var h = ~~(t/100);
  var m = t%100;

  if(a == "pm" && h < 12) h += 12;
  if(a == "am" && h == 12) h -= 12;
  date.setHours(h);
  date.setMinutes(m);
  return date;
}

function comp(a, b) {
  var da = parseDateTime(a.event_date, a.event_time);
  var db = parseDateTime(b.event_date, b.event_time);

  return da - db;
}

function parseTime(t) {
  var a = t.slice(-2);
  var t = +t.replace(/[apm:]/g, '');

  if(a == "pm" && ~~(t/100) < 12) t += 1200;
  if(a == "am" && ~~(t/100) == 12) t -= 1200;
  return t;
}

console.log(Date.parse('8:00pm'));
// NaN

console.log(parseTime('8:00am'));
console.log(parseTime('11:59am'));
console.log(parseTime('12:00pm'));
console.log(parseTime('12:01pm'));
// 800
// 1159
// 1200
// 1201

console.log(parseTime('8:00pm'));
console.log(parseTime('11:59pm'));
console.log(parseTime('12:00am'));
console.log(parseTime('12:01am'));
// 2000
// 2359
// 0
// 1

Вы можете использовать это :

function comp(a, b) {
    // Compare dates
    if (new Date(a.event_date).getTime() != new Date(b.event_date).getTime())
        return new Date(a.event_date) - new Date(b.event_date);

    // If dates are equal, compare hours
    return Date.parse(a.event_time) - Date.parse(b.event_time);
}

data=data.sort(comp)  

EDIT Я добавил пользовательский парсер дат (вдохновленный этим ) и сортировщик строк.

function parseDate(dateString) {
    var d = new Date();
    var time = dateString.match(/(\d+)(?::(\d\d))?\s*(p?)/);
    d.setHours( parseInt(time[1]) + (time[3] ? 12 : 0) );
    d.setMinutes( parseInt(time[2]) || 0 );
    return d;
}

function comp(a, b) {
    // Compare dates
    if (new Date(a.event_date).getTime() != new Date(b.event_date).getTime())
        return new Date(a.event_date) - new Date(b.event_date);

    // If dates are equal, compare hours
    var hourA = parseDate(a.event_time);
    var hourB = parseDate(b.event_time);
    if (hourA.getTime() != hourB.getTime())
        return hourA - hourB;

    // If hours are equal, compare titles
    if(a.title > b.title)
        return -1;
    else
        return 1;
}

Вы можете использовать момент .js для создания объектов даты для event_time

var sortedJ = _j.sort(function(a,b){

    var result = new Date(a.event_date) - new Date(b.event_date);

    if(result === 0)
    {
        return new moment("01/01/2000 "+a.event_time,"MM/DD/YYYY h:mm:ss a") - moment("01/01/2000 "+b.event_time,"MM/DD/YYYY h:mm:ss a");
    }

    return result;
});

Здесь работает JS FIDDLE

Вы можете попробовать это

function comp(a, b) {
    var diff = new Date(a.event_date) - new Date(b.event_date);
    if(diff < 0) return -1;
    else if(diff > 0) return 1;
    else if(parseTime(a.event_time) < parseTime(b.event_time)) return -1;
    else if(parseTime(a.event_time) > parseTime(b.event_time)) return 1;
    else return 0;
}

Но почему бы не сделать event_date и event_time одним свойством?

Правка:

Вы также можете определить для себя функцию sortBy, которая поможет вам Сортировать по любому произвольному числу свойств.

function sortBy(list, f) {
  list.sort(function(a, b) {
    var fa = f(a), fb = f(b);
    if(fa < fb) return -1;
    else if(fa > fb) return 1;
    else return 0;
  });
}

Затем вы можете сортировать по дате, времени и названию, как это

sortBy(list, function(o) {
  return [new Date(o.event_date), parseTime(o.event_time), o.title];
});

Comments

    Ничего не найдено.