Sort java script array of formatted date - javascript

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.

Related

Compare present date to previous/next date [duplicate]

I have two string dates in the format of m/d/yyyy. For example, “11/1/2012”, “1/2/2013”. I am writing a function in JavaScript to compare two string dates. The signature of my function is
bool isLater(string1, string2), if the date passed by string1 is later than the date passed by string2, it will return true, otherwise false.
So, isLater(“1/2/2013”, “11/1/2012”) should return true. How do I write a JavaScript function for this?
var d1 = Date.parse("2012-11-01");
var d2 = Date.parse("2012-11-04");
if (d1 < d2) {
alert ("Error!");
}
Demo Jsfiddle
Recently found out from a comment you can directly compare strings like below
if ("2012-11-01" < "2012-11-04") {
alert ("Error!");
}
You can simply compare 2 strings
function isLater(dateString1, dateString2) {
return dateString1 > dateString2
}
Then
isLater("2012-12-01", "2012-11-01")
returns true while
isLater("2012-12-01", "2013-11-01")
returns false
Parse the dates and compare them as you would numbers:
function isLater(str1, str2)
{
return new Date(str1) > new Date(str2);
}
If you need to support other date format consider a library such as date.js.
Directly parsing a date string that is not in yyyy-mm-dd format, like in the accepted answer does not work. The answer by vitran does work but has some JQuery mixed in so I reworked it a bit.
// Takes two strings as input, format is dd/mm/yyyy
// returns true if d1 is smaller than or equal to d2
function compareDates(d1, d2){
var parts =d1.split('/');
var d1 = Number(parts[2] + parts[1] + parts[0]);
parts = d2.split('/');
var d2 = Number(parts[2] + parts[1] + parts[0]);
return d1 <= d2;
}
P.S. would have commented directly to vitran's post but I don't have the rep to do that.
This worked for me in nextjs/react
import { format, parse, isBefore } from "date-fns";
...
{isBefore(new Date(currentDate), new Date(date)) ? (
<span>Upcoming Event</span>
) : (
<span>Past Event</span>
)}
...
isBefore(date, dateToCompare)
https://date-fns.org/docs/isBefore
You can use "Date.parse()" to properly compare the dates, but since in most of the comments people are trying to split the string and then trying to add up the digits and compare with obviously wrong logic -not completely.
Here's the trick. If you are breaking the string then compare the parts in nested format.
Compare year with year, month with month and day with day.
<pre><code>
var parts1 = "26/07/2020".split('/');
var parts2 = "26/07/2020".split('/');
var latest = false;
if (parseInt(parts1[2]) > parseInt(parts2[2])) {
latest = true;
} else if (parseInt(parts1[2]) == parseInt(parts2[2])) {
if (parseInt(parts1[1]) > parseInt(parts2[1])) {
latest = true;
} else if (parseInt(parts1[1]) == parseInt(parts2[1])) {
if (parseInt(parts1[0]) >= parseInt(parts2[0])) {
latest = true;
}
}
}
return latest;
</code></pre>
If your date is not in format standar yyyy-mm-dd (2017-02-06) for example 20/06/2016. You can use this code
var parts ='01/07/2016'.val().split('/');
var d1 = Number(parts[2] + parts[1] + parts[0]);
parts ='20/06/2016'.val().split('/');
var d2 = Number(parts[2] + parts[1] + parts[0]);
return d1 > d2

How to sort dates containing comma separated values?

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

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

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

Compare multiple date fields on a page through javascript

How to efficiently compare dynamic number of dates on a page from a given date?
Consider following code:
<div id="dateFields">
<input type="date" id="date1"/>
<input type="date" id="date2"/>
<input type="date" id="date3"/>
<input type="date" id="date4"/>
<input type="date" id="date5"/>
</div>
<div id="masterDate">
<input type="date" id="comparator"/>
</div>
<button onClick="compareDate()">Compare Now</button>
Consider the dates in div with id="dateFields are in random numbers. Say 5 for now. And the date in div with id="comparator is the date which we need to compare all the dates with.
Now, for example, if the comparator date is set to "March, 2015" and all the values in dateFields are set dynamically by the user (Say "Feb, 2002", "Dec, 2010", "Aug, 2016", "Jul, 2019" and "Nov, 2015"). What is the most efficient and generic code I should write in the function compareDate() so that the output brings all the dates which are greater than the comparator.
Edit:
Here is my javascript function. But, I don't feel that this is the efficient way. And even this is no good for dynamic number of values.
function compareDate() {
var v1 = document.getElementById("date1").value;
var v2 = document.getElementById("date2").value;
var v3 = document.getElementById("date3").value;
var v4 = document.getElementById("date4").value;
var v5 = document.getElementById("date5").value;
var v6 = document.getElementById("comparator").value;
var v7 = [ v1, v2, v3, v4, v5 ];
var result = "";
for (i = 0; i < v7.length; i++) {
console.log(solidify(v7[i]));
if (solidify(v6) < solidify(v7[i])) {
result += v7[i];
}
}
document.getElementById("result").innerHTML = result;
}
function solidify(date) {
var tempResult = '';
for (i = 0; i < date.length; i++) {
if (date.charAt(i) == '-') {
continue;
}
else {
tempResult += date.charAt(i);
}
}
return tempResult;
}
Edit 2:
Explanation of the requirement with example.
There need not be any text-box, it may be just a set of <td>, <p> or may be just a <div> containing number of dates, which may vary from minimum 2 dates to max 50 dates(Say).
I'm just looking for a logic and hence was trying with text-boxes.
For a real time example, consider a City Municipality Management System, which keeps track of monthly deaths that occur in that city. Now, a clerk wants to know the details of citizens who died after 15th of that month, how will he get the data?
The following code does what you are asking, but there are still some requirements that you need to nail down, in order to make it truly "generic" (see below the code):
HTML
<div id="dateFields">
<input type="date" id="date1"/>
<input type="date" id="date2"/>
<input type="date" id="date3"/>
<input type="date" id="date4"/>
<input type="date" id="date5"/>
</div>
<div id="masterDate">
<input type="date" id="comparator"/>
</div>
<div id="results">
Results: <span id="resultDates"></span>
</div>
<button onClick="compareDate()">Compare Now</button>
JavaScript
<script>
function compareDate() {
var aDates = document.getElementById("dateFields").getElementsByTagName("input");
var sCompareDate = document.getElementById("comparator").value;
var dCompareDate = formatDate(sCompareDate);
var result = "";
for (i = 0; i < aDates.length; i++) {
var sCurrDate = aDates[i].value;
if (dCompareDate < formatDate(sCurrDate)) {
if (result.length > 0) {
result += ", ";
}
result += sCurrDate;
}
}
if (result === "") {
result = "No dates less than " + sCompareDate;
}
document.getElementById("resultDates").innerHTML = result;
}
function formatDate(sDate) {
var regMonthYear = /[a-z]{3}, \d{4}/i;
if (regMonthYear.test(sDate)) {
sDate = sDate.replace(",", " 1,");
}
return new Date(sDate);
}
</script>
Things that need to be worked out still:
You must compare Date objects, not strings.
To do what you are trying to do, you must use JavaScript Date objects. Even if you are using am <input> with a type attribute of "date", its value is still a string. If you compare that, it would be like asking if "orange" is less than "house" . . . JavaScript will give you an answer, but it will be, in no way, related to what you are looking for.
The JavaScript Date object has built in comparison functionality that will do exactly what you are looking for.
2 You need to come up with some sort of standard for your date inputs and make sure that you have code to enforce them.
While the Date object is VERY flexible when it comes to what inputs it will accept when you are creating a new instance, it does have its limits. You can look at these two links for more information on valid string formats for creating dates:
the ISO date format - https://msdn.microsoft.com/en-us/library/ie/ff743760%28v=vs.94%29.aspx#ISO
other date parsing rules - https://msdn.microsoft.com/en-us/library/ie/ff743760%28v=vs.94%29.aspx#OtherDateFormats
Once you figured out which one(s) make the most sense for your needs, you really should set a common format (or group of formats) that you want to work with, and enforce that formatting on your inputs with validation rules. If you don't, you will have to add LOTS of logic to validate all of the different possibilities, so that you know that you are going to get a valid Date object when you try to create it.
3 You need to come up with some sort of standard output for your results.
Ideally, if you want to create a truly "generic" date comparison function to meet what you are asking for, you want it to focus solely on the comparison and nothing else. Something like this:
function compareDate(aDateGroup, dComparisonDate)
var aGreaterThanDates = [];
for (i = 0; i < aDateGroup.length; i++) {
if (dCompareDate < aDateGroup[i]) {
aGreaterThanDates.push(aDateGroup[i]);
}
}
return aGreaterThanDates;
}
. . . where aDateGroup is an array of Date objects and dCompareDate is a Date object as well.
The function would take in the dates, compare them, and pass back the ones that passed the test. Then you could cycle through the returned array and process those dates however you needed to.
This would also allow you to pass in dates from any source (i.e., like a collection of the <td>, <p>, and <div> elements that you mentioned in your second update), as long as they were converted to proper Date objects first.
Determine whether or not you need to be flexible in your comparison.
The above "ideal code" could actually be made even "more ideal" by adding some flexibility in the comparison function, by adding a few parameters to indicate what kind of comparison to do:
function compareDate(aDateGroup, dComparisonDate, sCompareDirection, bIncludeComparisonDate)
var aPassedDates = [];
for (i = 0; i < aDateGroup.length; i++) {
if (sCompareDirection === "before") {
if (bIncludeComparisonDate) {
if (dCompareDate >= aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
else {
if (dCompareDate > aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
}
else if (sCompareDirection === "after") {
if (bIncludeComparisonDate) {
if (dCompareDate <= aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
else {
if (dCompareDate < aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
}
else {
if (dCompareDate == aDateGroup[i]) {
aPassedDates.push(aDateGroup[i]);
}
}
}
return aPassedDates;
}
The sCompareDirection parameter would allow you to determine the direction of the comparison. "before" would check for values less than the comparison date, "after" would check for values greater than the comparison date, and any other value (or no value) would check for the dates being equal.
The bIncludeComparisonDate parameter would allow you to include the comparison date as part of the match. A value of true would turn the "greater than" comparison to "greater than or equal to" and the "less than" comparison to "less than or equal to".
Conclusion
Date comparison is actually a fairly common process, but it is also one that requires a LOT of thinking through to make flexible and foolproof. If you don't catch some of these things early, you are asking for a world of hurt down the line, when you try to reuse what you have built and in a situation that doesn't quite match what you originally set up. :)
you can do it in following way :
<script>
function compareDate() {
var v1 = document.getElementById("date1").value;
var v2 = document.getElementById("date2").value;
var v3 = document.getElementById("date3").value;
var v4 = document.getElementById("date4").value;
var v5 = document.getElementById("date5").value;
var v6 = document.getElementById("comparator").value;
var v7 = [ v1, v2, v3, v4, v5 ];
var finalResult = "";
for (k = 0; k < v7.length; k++) {
if (solidify(v6) < solidify(v7[k])) {
finalResult += v7[k];
finalResult += " and ";
}
}
document.getElementById("result").innerHTML = finalResult;
}
function solidify(date) {
var result = '';
for (i = 0; i < date.length; i++) {
if (date.charAt(i) == '-') {
continue;
} else {
result += date.charAt(i);
}
}
return result;
}
</script>
function compareDate() {
var dateFields = document.getElementById('dateFields').getElementsByTagName('input');
var comparatorDate = new Date(document.getElementById('comparator').value);
var rslt = [];
for (var i = 0; i < dateFields.length; i++) {
if (new Date(dateFields[i].value) > comparatorDate) rslt.push(dateFields[i].value);
}
return rslt;
}
This was tested in chrome

Categories