How to sort dates containing comma separated values? - javascript

I would like to know how can I sort dates in javascript containing comma-separated values in different order e.g.
var dates = "6/11/2015, 6/1/2015, 6/22/2015, 6/7/2015, 5/11/2015";
I want to order dates by latest dates like,
var dates2 = "5/11/2015, 6/1/2015, 6/7/2015, 6/11/2015, 6/22/2015";
Your help will be appreciated.
Thanks

You can split the string to get an array, sort them by passing each string to the Date constructor, and then join it back together.
let dates = "6/11/2015, 6/1/2015, 6/22/2015, 6/7/2015, 5/11/2015";
let res = dates.split(", ").sort((a,b)=>new Date(a) - new Date(b)).join(", ");
console.log(res);

The way I think, this could be done easily using split() to extract each day, month, year, and then, use those values to construct Dates objects. Finally, you compare and sort those dates.
const splitDatesByComma = dates.split(',').map((el) => el.trim())
const dates = splitDatesByComma.map((el) => {
const splitDate = el.split('/')
// Create a Date for splitted string. Month is 0 based
return new Date(splitDate[2], splitDate[1] - 1, splitDate[0], 0, 0, 0, 0)
})
const sortDatesDescending = dates.sort((dateA, dateB) => {
if (dateA > dateB) {
return -1
}
if (dateA < dateB) {
return 1
}
return 0
})
// Format sorted dates to string and join them.
const datesFormattedAndSorted = sortDatesDescending.map((date) => {
return `${date.getDate()}/${date.getMonth() + 1}/${date.getFullYear()}`
})
console.log(datesFormattedAndSorted.join(', '))
I've done this at CodePen with Vue if anyone is interested: https://codepen.io/LucasFer/pen/mdMmqrN

Related

Combine array of dates sorted in ascending order into array of date ranges

I have one array of dates, I want to create object containing start and end by checking continue dates.
EX.
dateArray = [
"2020-01-22T00:00:00.000Z",
"2020-01-23T00:00:00.000Z",
"2020-01-28T00:00:00.000Z",
"2020-01-29T00:00:00.000Z",
"2020-01-30T00:00:00.000Z",
"2020-01-31T00:00:00.000Z",
"2020-02-01T00:00:00.000Z",
"2020-02-02T00:00:00.000Z",
"2020-02-03T00:00:00.000Z",
"2020-02-04T00:00:00.000Z",
"2020-02-05T00:00:00.000Z",
"2020-02-06T00:00:00.000Z",
"2020-02-07T00:00:00.000Z",
"2020-02-16T00:00:00.000Z",
"2020-02-17T00:00:00.000Z",
"2020-02-18T00:00:00.000Z",
"2020-02-19T00:00:00.000Z",
"2020-02-20T00:00:00.000Z"
]
myRequirement = [{
start: "2020-01-22T00:00:00.000Z",
end: "2020-01-23T00:00:00.000Z"
},
{
start: "2020-01-28T00:00:00.000Z",
end: "2020-02-07T00:00:00.000Z"
},
{
start: "2020-02-16T00:00:00.000Z",
end: "2020-02-20T00:00:00.000Z"
}
]
I want to do this using in node.js.
I tried this using some nested for loops.
First i am running loop on main dateArray, Then checking is it first date or not, If it is first date then storing it as first objects start date, Then in next date case checking is it next most date of previous date or not.
let gapArray = [];
let startEndObj = {};
let tempStartDate;
let tempEndDate;
let tempNextDate;
await asyncForEach(finalAvailablityDatesArrayOFi.availeblityDatesArray, async (availeblityDatesArrayOFi) => {
console.log("availeblityDatesArrayOFi", availeblityDatesArrayOFi);
if (!tempStartDate) {
console.log("In if");
startEndObj.startDate = availeblityDatesArrayOFi;
tempStartDate = availeblityDatesArrayOFi;
let oneDatePlus = new Date(availeblityDatesArrayOFi).setDate(new Date(availeblityDatesArrayOFi).getDate() + 1);
tempNextDate = new Date(oneDatePlus);
console.log("startEndObj", startEndObj);
}
else if (tempStartDate) {
console.log("in else");
if (new Date(availeblityDatesArrayOFi).getTime() == new Date(tempNextDate).getTime()) {
console.log("Do nothing!");
tempStartDate = availeblityDatesArrayOFi;
tempEndDate = availeblityDatesArrayOFi;
let oneDatePlus = new Date(availeblityDatesArrayOFi).setDate(new Date(availeblityDatesArrayOFi).getDate() + 1);
tempNextDate = new Date(oneDatePlus);
}
else {
startEndObj.endDate = new Date(tempEndDate);
gapArray.push(startEndObj);
tempStartDate = '';
tempEndDate = '';
startEndObj = {};
}
}
});
Thank you!
Looks like a job for Array.prototype.reduce().
Note: hereafter assumption is made that few prerequisites are met:
source array items are valid ISO-formatted date strings or others, parseable by new Date() constructor, otherwise should be brought to one of supported format
source array items are sorted in ascending order, otherwise Array.prototype.sort() method must be applied in advance
array items do not include time of the day part (or this part is exactly the same for all items), otherwise consecutive date records may happen to have difference greater than 864e5 milliseconds (1 day) and more complex comparison is required
You may walk through your array and compare current items with previous/following, once you have a gap greater than 1 day you push new range into resulting array or modify end date for the last one:
const src = ["2020-01-22T00:00:00.000Z","2020-01-23T00:00:00.000Z","2020-01-28T00:00:00.000Z","2020-01-29T00:00:00.000Z","2020-01-30T00:00:00.000Z","2020-01-31T00:00:00.000Z","2020-02-01T00:00:00.000Z","2020-02-02T00:00:00.000Z","2020-02-03T00:00:00.000Z","2020-02-04T00:00:00.000Z","2020-02-05T00:00:00.000Z","2020-02-06T00:00:00.000Z","2020-02-07T00:00:00.000Z","2020-02-16T00:00:00.000Z","2020-02-17T00:00:00.000Z","2020-02-18T00:00:00.000Z","2020-02-19T00:00:00.000Z","2020-02-20T00:00:00.000Z"],
ranges = src.reduce((res,date,idx,self) => {
const rangeStart = !idx || new Date(date) - new Date(self[idx-1]) > 864e5,
rangeEnd = idx == self.length-1 || new Date(self[idx+1]) - new Date(date) > 864e5
if(rangeStart) res.push({startdate:date,enddate:date})
else if(rangeEnd) res[res.length-1]['enddate'] = date
return res
}, [])
console.log(ranges)
.as-console-wrapper {min-height:100%}
You need to be careful with this type of processing to determine all the business rules exactly. If the time component is not to be considered, then it should be removed, otherwise when comparing say 2020-01-01T00:00:00 to 2020-01-02T012:00:00 you will get a difference greater than 1 day but might not want it to be treated as the start of a new range.
For that reason, the "days difference" logic should be in a separate function, which also makes it easier to change date libraries if you're using one. The days difference is also signed, so make sure they are passed in the right order.
Otherwise, the following is pretty much the same as Yevgen's answer but a little more efficient I think as it only creates two Dates on each iteration instead of four.
let dateArray = [
"2020-01-22T00:00:00.000Z",
"2020-01-23T00:00:00.000Z",
"2020-01-28T00:00:00.000Z",
"2020-01-29T00:00:00.000Z",
"2020-01-30T00:00:00.000Z",
"2020-01-31T00:00:00.000Z",
"2020-02-01T00:00:00.000Z",
"2020-02-02T00:00:00.000Z",
"2020-02-03T00:00:00.000Z",
"2020-02-04T00:00:00.000Z",
"2020-02-05T00:00:00.000Z",
"2020-02-06T00:00:00.000Z",
"2020-02-07T00:00:00.000Z",
"2020-02-16T00:00:00.000Z",
"2020-02-17T00:00:00.000Z",
"2020-02-18T00:00:00.000Z",
"2020-02-19T00:00:00.000Z",
"2020-02-20T00:00:00.000Z"
];
// Simple difference in days function
function daysDiff(d0, d1) {
return Math.round((d1 - d0) / 8.64e7);
}
let ranges = dateArray.reduce((acc, curr, i, arr) => {
// If first date, initialise first object
if (!acc.length) {
acc.push({start: curr, end: curr});
} else {
let d0 = new Date(curr);
let d1 = new Date(arr[i-1]);
// If difference greater than 1 day, end previous range
// and start a new range
if (daysDiff(d1, d0) > 1) {
acc[acc.length - 1].end = arr[i-1];
acc.push({start: curr, end: curr});
}
}
return acc;
}, []);
console.log(ranges);

Checking if date text has milliseconds and seconds in momentjs

I am trying to parse a date from a text format to see if milliseconds and seconds were included in it.
For e.g.
let text = '2016-02-02 14:30:34.234';
const timezone = 'America/Los_Angeles';
// const hasMS = utcParse('%Y-%m-%d %H:%M:%S.')(text);
// const hasSeconds = utcParse('%Y-%m-%d %H:%M:')(text);
const hasMS = !!moment.tz(text, 'YYYY-MM-DD HH:MM:ss.', timezone);
console.log('hasMS', hasMS);
const hasSeconds = !!moment.tz(text, 'YYYY-MM-DD HH:MM:', timezone);
console.log('hasSeconds', hasSeconds);
Basically I am trying to replace the commented code. utcParse() from d3.time-format would check if the date text has milliseconds and seconds in it. I tried a couple of things for momentjs library, but it doesn't seem to work.
By using Regular expressions you can check if certain parts of the string are present.
If you call matchDateTime() with the string you get an array back with all the matched groups.
let text_min = '2016-02-02 14:30';
let text_sec = '2016-02-02 14:30:34';
let text_ms = '2016-02-02 14:30:34.234';
function matchDateTime(text) { return text.match(/(\d{4})-(\d\d)-(\d\d) (\d\d):(\d\d)(?::(\d\d)(?:\.(\d\d\d))?)?/); }
function hasSeconds(text) { return !!matchDateTime(text)[6]; }
function hasMilliSeconds(text) { return !!matchDateTime(text)[7]; }
function testTimeString(text) {
console.log(text, "hasSeconds=", hasSeconds(text));
console.log(text, "hasMilliSeconds=", hasMilliSeconds(text));
}
testTimeString(text_min);
testTimeString(text_sec);
testTimeString(text_ms);
console.log(matchDateTime(text_ms));

comparing two arrays for intersecting values

I'm trying to use JavaScript to compare 2 different arrays and test for intersecting values.
This array contains ranges of times of availability for a 7 day week. In the availability array below each key represents a day of the week starting with Sunday. So key 0 = Sunday, key 1 = Monday..... maximum number of keys would be 6 which = Saturday
var availability = [["8:30AM-12PM","2PM-6PM"],
["6:15AM-9:30AM","1PM-4PM","8PM-11:15PM"],[],["9AM-9PM"]];
The below array need1 contains ranges of times of need for specific days throughout the week (anywhere from Sunday{key0} to Saturday{key6}). It uses the same key format as the above availability array. need1 array should match within the times and days listed in the availability array. So when comparing need1 to availability a match should be found.
var need1 = [["9AM-11:30AM","3PM-5PM"],[],[],["2PM-6:30PM"]]; //matches
The below array need2 is an example of an non-match, since the times of need ranges are outside the ranges of times and days listed in the availability array. So when comparing need2 to availability NO match should be found.
var need2 = [["7:30AM-11:30AM"],[],[],["2PM-6:30PM", "8PM-10:30PM"]]; //does not match
I'm trying to figure out how to compare these 2 arrays to match up the need ranges with the availability ranges. Meaning the need ranges have to completely fit inside the availability ranges for each day. All I'm looking for is a simple true or false returned value when comparing. true = match and false = NOT a match. However, I have no idea how to to efficiently do this. Any help would be appreciated!
Also, If need be I can lay out the array values in a different format if it would make comparing them easier. i.e. using date values instead of strings, or 24 hour format instead of 12 hour format
I'm going to take a risk here and take a slightly different approach than you've started with, but which provides a solution to your basic question: are there any matches between the available times and the needed times?
Before I present code, here are some recommendations:
1. Use an Object at the top level, not an array. Using array positions as meaningful is dangerous. Instead utilize the power of JavaScript object literals.
2. Separate your start and stop times, do not put them in the same string.
3. Utilize the power of native Array methods.
I make these recommendations and provide the following code snippet as it seems that you have some wiggle room in how you approach the problem.
UPDATED
Changed assumption per request. Only returns match for a given day, if every needed start/time slot finds a matched time slot in the availability object.
Something like the following should get you where you want to go. This will return an object of the matched needs.
/* structure your schedule as objects with arrays of objects of start/stop times */
const availability1 = {
sunday: [
{
start: '08:30',
stop: '12:00'
},
{
start: '14:00',
stop: '18:00'
}
],
monday: [{
start: '06:25',
stop: '11:45'
}],
wednesday: []
};
const need1 = {
// will be matched, every needed time slot is within an availability slot
// on the same day
sunday: [
{
start: '09:45', // has a match
stop: '12:00'
},
{
start: '14:00', // has a match
stop: '18:00'
}
],
monday: [ // will not be matched because...
{
start: '14:00', // has NO match
stop: '16:00'
},
{
start: '07:00', // has a match
stop: '10:00'
}
],
tuesday: []
};
const getMinutes = (timeString) => {
const timeParts = timeString.split(':');
const hours = Number(timeParts[0]);
const minutes = Number(timeParts[1]);
const timeInMinutes = (hours * 60) + minutes;
// console.log(`timeInMinutes: ${timeInMinutes}`);
return timeInMinutes;
}
const isTimeMatch = (availabilityTime, needTime) => {
const availStart = getMinutes(availabilityTime.start);
const availStop = getMinutes(availabilityTime.stop);
const needStart = getMinutes(needTime.start);
const needStop = getMinutes(needTime.stop);
console.log(`Availibility ${availabilityTime.start} (${availStart}) - ${availabilityTime.stop} (${availStop})`)
console.log(`Need ${needTime.start} (${needStart}) - ${needTime.stop} (${needStop})`)
const startTimeMatch = availStart <= needStart;
const stopTimeMatch = availStop >= needStop;
const isMatch = startTimeMatch && stopTimeMatch;
console.log(`is match: ${isMatch}`);
return isMatch;
};
const compareDays = (availTimes, needTimes) => {
return needTimes.map((needTime, i) => {
const matches = availTimes.filter((availTime) => {
return (isTimeMatch(availTime, needTime));
});
needTime.match = matches.length > 0;
return needTime;
}).filter((needTime, i, allNeedTimes) => {
return (allNeedTimes.every((i) => i.match === true));
});
}
function findMatches(availability, need) {
const matches = Object.keys(availability).reduce((accumulator, day) => {
if (availability[day] && need[day]) {
console.log(`Possible matches found on ${day}`)
const matches = compareDays(availability[day], need[day]);
if (matches.length > 0) {
accumulator[day] = matches;
}
}
return accumulator;
}, {});
return (Object.keys(matches).length === 0) ?
false : matches;
}
const matchedTimes = findMatches(availability1, need1);
if (matchedTimes) {
console.log('The following needs match availability:');
console.log(matchedTimes);
} else {
console.log('No matches found');
}

Compare dates as strings in typescript

I am trying to compare two dates as strings in typescript. The input I have is as below :-
startWindow = '05/2014'
endWindow = '05/2018'
I need to write a function to check if the start Window is greater than the end Window.
Both the inputs are of string type.
Thanks
You can convert it to a date and then compare them:
function convertDate(d)
{
var parts = d.split('/');
return new Date(parts[1], parts[0]);
}
var start = convertDate('05/2014');
var end = convertDate('05/2018');
alert(start < end);

Sort java script array of formatted date

I have an javascript array of date which is formatted in a particular way like MM/DD/YYYY. How can I use javascript sort function to sort this array?
You can use Array.sort, but you need to pass a custom comparison function which converts the values to Dates and compares those, instead of just the string value:
var arr = ['07/01/2014', '04/02/2014', '12/11/2013'];
arr.sort(function(a, b) {
// convert both arguments to a date
var da = new Date(a);
var db = new Date(b);
// do standard comparison checks
if(da < db) {
return -1;
} else if(da > db) {
return 1;
} else {
return 0;
}
});
// print the result
var result = document.getElementById('result');
for(var i = 0; i < arr.length; ++i)
{
result.value = result.value + '\n' + arr[i];
}
<textarea id="result" rows="5" cols="50"></textarea>
Are the dates stored as strings or as Date objects? You can convert each string into a date object by using the Date constructor like new Date('MM/DD/YYYY'). This will give you Date objects and make it much easier to compare. To compare Dates and sort them, just grab their values using the getTime() function to get their value in milliseconds and compare the numbers.

Categories