0

I have an array of objects

var data =[
  {
    "avail": "3 Bookings Available" 
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  }];

I want to sort data by its time string value so that the required output becomes like this below:

 [{
    "avail": "3 Bookings Available" 
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  }]

I have used the sort function with String #localeCompare but still i am not getting the required output

data.sort(function(a,b){
  return a.time.localeCompare(b.time);
});
console.log(data);

even i used the String#slice() method by which i can be used to generate the valid date string using '1970/01/01' as an arbitrary date still i am getting the required out can anyone give me the way by which i can get the output in this manner Thanks in advance.

data.sort(function(a, b) {
  return Date.parse('1970/01/01 ' + a.time.slice(0, -2) + ' ' + a.time.slice(-2)) - Date.parse('1970/01/01 ' + b.time.slice(0, -2) + ' ' + b.time.slice(-2))
});

Example:

var data = [{
    "avail": "3 Bookings Available",
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  }
];

data.sort(function(a, b) {
  return Date.parse('1970/01/01 ' + a.time.slice(0, -2) + ' ' + a.time.slice(-2)) - Date.parse('1970/01/01 ' + b.time.slice(0, -2) + ' ' + b.time.slice(-2))
});
console.log(data)

1
  • I take it you don't have control over the server response? If you did, you could send back ISO8601 format which can be used to construct a Date with a dateString easily i.e. new Date("2018-01-30T12:34:56") Commented Jan 30, 2018 at 14:28

6 Answers 6

3

I'd have a functon to turn those times into minutes-since-midnight, something roughly like:

function parseTime(time) {
  var parts = time.match(/^(\d{2}):(\d{2}) (AM|PM)/i);
  if (!parts) {
    return NaN;
  }
  var adjust = parts[3].toUpperCase() == "PM" ? 12 : 0;
  return (parseInt(parts[1], 10) + adjust) * 60 + parseInt(parts[2], 10);
}

Then the sorting is straightforward:

data.sort(function(a, b) {
  return parseTime(a.time) - parseTime(b.time);
});

Example:

var data =[
  {
    "avail": "3 Bookings Available",
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  }];
function parseTime(time) {
  var parts = time.match(/^(\d{2}):(\d{2}) (AM|PM)/i);
  if (!parts) {
    return NaN;
  }
  var adjust = parts[3].toUpperCase() == "PM" ? 12 : 0;
  return (parseInt(parts[1], 10) + adjust) * 60 + parseInt(parts[2], 10);
}
data.sort(function(a, b) {
  return parseTime(a.time) - parseTime(b.time);
});
console.log(data);
.as-console-wrapper {
  max-height: 100% !important;
}

Classic divide-and-conquer (e.g., break the problem into smaller pieces).

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

Comments

2

This works (after adding a missing comma):

var data = [{
    "avail": "3 Bookings Available",
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  }
];

data.sort(function(a, b) {
  const [afrom, ato]=a.time.split(" to ");
  const [bfrom, bto]=b.time.split(" to ");
  return Date.parse(a.date + " " + afrom) - Date.parse(b.date + " "+  bfrom);  
});
console.log(data)

Comments

1

Normal string comparison is fine for this, but you need to re-arrange the AM or PM at the beginning of the time string(use String#replace method for that).

var data = [{  "avail": "3 Bookings Available", "time": "05:00 PM to 06:00 PM",  "date": "2018-01-30"}, {  "avail": "3 Bookings Available",  "time": "09:00 AM to 10:00 AM",  "date": "2018-01-30"}, {  "avail": "3 Bookings Available",  "time": "04:00 PM to 05:00 PM",  "date": "2018-01-30"}, {  "avail": "3 Bookings Available",  "time": "03:00 PM to 04:00 PM",  "date": "2018-01-30"}];

data.sort(function(a, b) {
  // compare the date string
  return a.date.localeCompare(b.date) ||
    // in case they are equal then compare time string
    // after converting the format
    timeFormat(a).localeCompare(timeFormat(b))
});

// function for formating the time string
function timeFormat(o) {
  // reposition the AM or PM at the beginning of time
  // for string comparison
  return o.time.replace(/(\d{2}:\d{2}\s)(AM|PM)/g, '$2$1');
}

console.log(data);

Comments

0

You could merge date and time and create a date object of which you can get the time in milliseconds since 1970, compare these numbers and sort your array accordingly.

Comments

0

With a helper function toMilitary you can change the time to a number between 0 and 2359. Then map the original data to military time and index. Then sort on the military time. And at last reduce the result using the indexes of the sorted set to pick items from the original data.

Following code does not mutate any of the original data.

    const data =[
      {
        "avail": "3 Bookings Available",
        "time": "05:00 PM to 06:00 PM",
        "date": "2018-01-30"
      },
      {
        "avail": "3 Bookings Available",
        "time": "09:00 AM to 10:00 AM",
        "date": "2018-01-30"
      },
      {
        "avail": "3 Bookings Available",
        "time": "04:00 PM to 05:00 PM",
        "date": "2018-01-30"
      },
      {
        "avail": "3 Bookings Available",
        "time": "03:00 PM to 04:00 PM",
        "date": "2018-01-30"
      }
    ];

    const toMilitary = timeString => {
      const time = timeString.slice(0,8);
      const amPm = time.slice(-2).toLowerCase();
      const timeNumber = parseInt(time.replace(/[^0-9]/g,""),10);
      return (amPm==="pm")?timeNumber+1200:timeNumber;
    };

    const sortedData = data
    .map((d,index)=>[
      toMilitary(d.time), index
    ])
    .sort((a,b)=>a[0]-b[0])
    .reduce(
      (all,[_,index])=>
        all.concat([data[index]]),
      []
    );
    console.log(JSON.stringify(sortedData,undefined,2))

I like mplungjan way and it includes the date. It will call the parsing date and time function many times while sorting so I've implemented it instead of military from the previous. First calculate full date and time for all objects and pair with index, then sort, then pick items from data using the indexes of the sorted result:

const data =[
  {
    "avail": "3 Bookings Available",
    "time": "05:00 PM to 06:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "09:00 AM to 10:00 AM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "04:00 PM to 05:00 PM",
    "date": "2018-01-30"
  },
  {
    "avail": "3 Bookings Available",
    "time": "03:00 PM to 04:00 PM",
    "date": "2018-01-30"
  }
];

const fullDate = item => {
  const [from, to]=item.time.split(" to ");
  return Date.parse(item.date + " " + from);
};

const sortedData = data
.map((d,index)=>[
  fullDate(d),index
])
.sort((a,b)=>a[0]-b[0])
.reduce(
  (all,[_,index])=>
    all.concat([data[index]]),
  []
);
console.log(JSON.stringify(sortedData,undefined,2))

Comments

0

Here's a simple example using moment.js to parse with a custom format:

var data = [
  { "time": "05:00 PM to 06:00 PM", "date": "2018-01-30" },
  { "time": "09:00 AM to 10:00 AM", "date": "2018-01-30" },
  { "time": "04:00 PM to 05:00 PM", "date": "2018-01-30" },
  { "time": "03:00 PM to 04:00 PM", "date": "2018-01-30" }
];

data.sort(function(a, b) {
  let format = "YYYY-MM-DD hh:mm A";
  let ma = moment(a.date + " " + a.time, [format])
  let mb = moment(b.date + " " + b.time, [format])
  return ma.diff(mb);
});

console.log(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>

Here's another example which also includes the end time in the sort (if two start date/times are equal):

var data = [
  { "time": "09:00 PM to 06:00 PM", "date": "2018-01-30" },
  { "time": "09:00 PM to 10:00 AM", "date": "2018-01-30" },
  { "time": "09:00 PM to 05:00 PM", "date": "2018-01-30" },
  { "time": "09:00 PM to 04:00 PM", "date": "2018-01-30" }
];

data.sort(function(a, b) {
  let format = "YYYY-MM-DD hh:mm A";
  let ma = moment(a.date + " " + a.time, [format])
  let mb = moment(b.date + " " + b.time, [format])
  let diff = ma.diff(mb);
  if(diff === 0) {
    ma = moment(a.date + " " + a.time.substring(12), [format])
    mb = moment(b.date + " " + b.time.substring(12), [format])
    diff = ma.diff(mb);
  }

  return diff;
});

console.log(data);
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.20.1/moment.min.js"></script>

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.