Javascript sorting dates in the wrong order - javascript

I can't figure out why Javascript (running in Chrome, Safari, or NodeJS) seemingly sorts these dates incorrectly:
> [
"2014-05-01T08:06:00.000Z",
"2014-05-01T06:26:00.000Z",
"2014-05-01T06:27:00.000Z"
].map(function(x) {return new Date(x)}).sort()
produces
[ Thu May 01 2014 01:06:00 GMT-0700 (PDT),
Wed Apr 30 2014 23:26:00 GMT-0700 (PDT),
Wed Apr 30 2014 23:27:00 GMT-0700 (PDT) ]
I have looked for odd time changes around that date but can't find any.

Simply calling sort method will basically sorting based on string comparison. So for sorting based on date object use custom sort function.
console.log(
[
"2014-05-01T08:06:00.000Z",
"2014-05-01T06:26:00.000Z",
"2014-05-01T06:27:00.000Z"
].map(function(x) {
return new Date(x)
}).sort(function(a, b) {
return a - b;
})
)
If you want to sort the original array then avoid map method and inside the compare function parse the date string before taking difference.
console.log(
[
"2014-05-01T08:06:00.000Z",
"2014-05-01T06:26:00.000Z",
"2014-05-01T06:27:00.000Z"
].sort(function(a, b) {
return new Date(a) - new Date(b);
})
)

Array.prototype.sort takes a callback which can return negative, positive or zero value to sort the target array.
[
"2014-05-01T08:06:00.000Z",
"2014-05-01T06:26:00.000Z",
"2014-05-01T06:27:00.000Z"
].sort(function(a, b){
return (new Date(b) - new Date(a));
})

Related

Figuring out why Date.parse() does not equal comparison date

When I compare arriveDate1 to holiday they are not equal and I'm not sure why. In the console both dates appear the same. Any ideas why this might be? (using Date.js).
var orderShip1 = Date.today(); //date it ships
var arriveDate1 = orderShip1.addDays(3); //first day it could arrive
var holiday = Date.parse('8/8/2014');
console.log(arriveDate1); // Fri Aug 08 2014 00:00:00 GMT-0400 (EDT)
console.log(holiday); // Fri Aug 08 2014 00:00:00 GMT-0400 (EDT)
if (arriveDate1 === holiday) {
orderShip1.addDays(1);
//arriveDate1 = orderShip1.addDays(1);
}
This happens because when you check with the == and === operators, Javascript performs a check by reference. This two objects, unless they are declared like holiday = arriveDate1, will then never be equal, because they don't share the same memory reference.
Example:
a = {foo: 'hello'};
b = {foo: 'hello'};
a == b;
> false
You should perform the check using .toISOString or the unary operator + to convert the data objects in milliseconds, like this:
// this
if (arriveDate1.toISOString() == holiday.toISOString()) ...
// or this
if (+arriveDate1 == +holiday) ...
The triple equals sign tests if objects are identical, that is they are the same object. Try double equals.

Javascript date less than or equal to returning only less than

I have a jQuery datepicker tool returning back a maximum and a minimum date.
The dates are to filter out results from an array. I use jQuery.grep to filter based on the date. For some reason, while >= will work, <= only returns less than.
// Function to filter based on date minimum
function filterListGreaterThan(filter, list, min){
var result = jQuery.grep(list, function (obj){
return new Date(obj[filter]) >= min;
});
return result;
};
function filterListLessThan(filter, list, max){
var result = jQuery.grep(list, function (obj){
return new Date(obj[filter]) <= max;
});
return result;
};
So if i put in Nov 1, 2013 - Nov 5, 2013 it will only return Nov 1 - Nov 4... and I have no idea why.
Edit: Mac gave me the correct answer. When comparing the dates jQuery Sets the time to midnight. So even though I had it searching on the correct day it was not looking past midnight. This is the Corrected function:
// Function to filter based on date maximum
function filterListLessThan(filter, list, max){
var result = jQuery.grep(list, function (obj){
//add time to date because jQuery sets the time at 00:00:00
max.setHours(23,59,59);
return new Date(obj[filter]) <= max;
})
return result;
};
It seems the problem is likely due to the max date having a time component set to 00:00 AM - all items in the array occurring on the max date are probably being filtered out because they occur some time after 00:00 AM.
To fix this, the best approach is either to change the max date to have a time component of 11:59:59 PM, or to set the max date to 00:00 AM the following day and use a less-than (rather than a less-than-or-equal).
Not entirely sure I understand what you are trying to do, so apologies if this is not what you need but if you just want to filter an array of dates I'd try something like below.
You need to make sure you are comparing a Date object with another Date object and that the values in your array are formatted so as to make a valid Date object.
I'm not sure how that jQuery function works but using vanilla javascript I would do something like this to filter dates:
var list = ['2013,10,01','2013,10,02','2013,10,03','2013,10,04','2013,10,05',
'2013,10,06'];
function filterListGreaterThan(list, min_date){
var filtered_dates = [];
for(var i=0; i < list.length; i++){
var parts = list[i].split(','),
test_date = new Date(parts[0],parts[1],parts[2]);
if(test_date >= min_date){
filtered_dates.push(test_date);
}
}
return filtered_dates;
}
var min_date = new Date('2013','10','04'),
dates = filterListGreaterThan2(list, min_date);
console.log(dates);
//RETURNS:
//Mon Nov 04 2013 00:00:00 GMT+0000 (GMT Standard Time)
//Tue Nov 05 2013 00:00:00 GMT+0000 (GMT Standard Time)
//Wed Nov 06 2013 00:00:00 GMT+0000 (GMT Standard Time)
//

Converting a string into a date

I have the following script which joins 2 feeds and displays them on the screen
$.when( //get feed 1, //get feed 2 ).done(function(a1, a2){
var data = a1[0]response.Data.feed.entries.concat(a2[0].responseData.feed.entries);
var sorted = data.sort(function(a, b) {
if(a.publishedDate > b.publishedDate) {
return 1
}
if(a.publishedDate < b.publishedDate) {
return -1
}
return 0
});
for( i = o; i <= sorted.length - 1; i++ ) {
document.write(sorted[i].title);
document.write(sorted[i].publishedDate);
}
});
This returns all the rows, but it doesn't sort the rows. The sorting seems completely random. I'm assuming it's because the dates are formatted as follows in the JSON data:
Mon, 23 Sep 2013 04:37:45 -0700
What does that -0700 mean
How do I convert that date string into a proper date object so I can sort the results correctly?
-0700 means the UTC offset UTC-07:00.
I'm strongly recommend you to use Moment.js library to deal with date and time, formatting and conversions to make your "Date & Time JavaScript Life" easy and funny.
As Alnitak said this particular format is accepted by Date.parse therefore if you use one of accepted formats you can just use native JavaScript for sorting.
var dateStrings,
sortDates;
dateStrings = [
'Mon, 23 Sep 2013 04:37:45 -0700',
'Sun, 22 Sep 2013 05:27:32 +0300',
'Mon, 23 Sep 2013 03:14:17 -0700'
];
sortDates = function(dateStrings) {
return dateStrings.sort(function(a, b) {
return new Date(a) - new Date(b);
});
};
console.log(sortDates(dateStrings));
Fiddle
The variable sorted in your code snippet could be properly retrieved in this way:
var sorted = data.sort(function(a, b) {
return new Date(a.publishedDate) - new Date(b.publishedDate);
});
Well, -0700 means.. is 7 hours earlier than Greenwich Mean ...yor can check more in wikipedia
And if you want to convert any date properly, i strongly recommend you to use the library DateJS (http://www.datejs.com/)
You can use syntatic sugarr..!! to create your object...
Date.parse('Thu, 1 July 2013 20:20:20');
voila.. its very easy...
You can pass the string to new Date(...) to convert to a real Date object.
To sort however you also need to pass a specific sort function because default Javascript sort on arrays just converts elements to string and compares the result of conversion (thus any "Mon"day will happen to be placed before any "Sun"day).
Something that should work is
dates.sort(function(a, b){ return a - b; });

How to compare two dates (MonthName YearNumber) in javascript

This functionality is working fine in Chrome... But not IE or FF.
I am trying to validate two fields that take the value of MonthName YearNumber (see screenshot).
I am using Date.parse() to get miliseconds, then compare if Start Date <= End Date.
function IsStartEndDtError(StartDt, EndDt) {
//convert dates to miliseconds to compare if one is greater than other
var StartDtMili = Date.parse(StartDt);
var EndDtMili = Date.parse(EndDt);
if (StartDtMili <= EndDtMili) {
return false;
}
else {
return true;
}
}
What appears in Firebug:
Since the format your date is in isn't universally supported you can try a library like Date.js:
Date.parse("November 2012")
// returns: Thu Nov 01 2012 00:00:00 GMT+0000 (GMT)
If you don't want another library you can manually replace the month names with numbers and create a new date string.
Ecmascript does not seem to support full month names, if you look at "Section 15.9.1.15 Date Time String Format" in the spec.
In Firefox:
new Date("November 2012")
// Invalid Date
new Date("2012-11")
// Thu Nov 01 2012 00:00:00 GMT+0000 (GMT)
The second date format should be standardized across browsers, the first isn't.
11 1999, November 1999 are not parsable formats. You either need to use a date library that is more flexible with its input formats, or process your input and identify the parts in it:
function IsStartEndDtError(StartDt, EndDt) {
var months = {
January: 0,
February: 1,
...
};
//convert dates to miliseconds to compare if one is greater than other
var StartDtMili = (new Date(StartDt.split(" ")[1], month[StartDt.split(" ")[0]])).getTime();
var EndDtMili = (new Date(EndDt.split(" ")[1], month[EndDt.split(" ")[0]])).getTime();
if (StartDtMili <= EndDtMili) {
return false;
}
else {
return true;
}
}

Overriding the Javascript Date constructor?

I am developing a browser application that is sensitive to the current date.
Throughout my application's code, I call new Date and perform calculations based on the current time and render the view accordingly.
In order to test my application for different potential calendar days, I would have to constantly change my system clock to the past or future, which is an annoyance and probably not healthy for my computer.
So purely for testing purposes (I would never use this code in production), I decided to override the built-in Date constructor by doing this in the console:
// create a date object for this Friday:
var d = new Date(2012, 0, 20)
//override Date constructor so all newly constructed dates return this Friday
Date = function(){return d}
With this assumption in mind, I tried this and got strange results:
var now = new Date
Sat Apr 07 2012 00:00:00 GMT-0400 (EDT)
now = new Date
Tue Jul 10 2012 00:00:00 GMT-0400 (EDT)
now = new Date
Wed Jul 09 2014 00:00:00 GMT-0400 (EDT)
now = new Date
Wed Jun 07 2023 00:00:00 GMT-0400 (EDT)
...and so on....
My question is, what exactly is going on here?
If I overrode the constructor to return a static date, why does it give unrelated and constantly incrementing dates?
Also, is there an effective way I can override the Date constructor to return a static date in the future without having to go through all date instantiation calls in my code and modifying the output?
Thanks in advance.
EDIT:
I tried my code in a fresh window and it worked as expected.
It seems the culprit was the jQuery UI datepicker plugin which was calling its "refresh" method. When I disable its call, the date overriding works normally, but as soon as I use the datepicker, the strange behavior above occurs.
No idea why this popular plugin would somehow affect something global like this. If anyone has any ideas, let me know.
Sorry for not figuring out the true culprit earlier.
I also faced this problem and ended up writing a module for that. Perhaps it's useful for somebody:
Github: https://github.com/schickling/timemachine
timemachine.config({
dateString: 'December 25, 1991 13:12:59'
});
console.log(new Date()); // December 25, 1991 13:12:59
I tested your code:
// create a date object for this Friday:
var d = new Date(2012, 0, 20);
//override Date constructor so all newly constructed dates return this Friday
Date = function(){return d;};
var now = new Date()
console.log(now);
now = new Date()
console.log(now);
now = new Date()
console.log(now);
now = new Date()
console.log(now);
And the result ???? Why so different?
Date {Fri Jan 20 2012 00:00:00 GMT+0700 (SE Asia Standard Time)}
Date {Fri Jan 20 2012 00:00:00 GMT+0700 (SE Asia Standard Time)}
Date {Fri Jan 20 2012 00:00:00 GMT+0700 (SE Asia Standard Time)}
Date {Fri Jan 20 2012 00:00:00 GMT+0700 (SE Asia Standard Time)}
EDIT:
I saw that whenever you interact with the Date Picker, the behavior goes different. Try another test, change the now is something like interact with Date Picker:
// create a date object for this Friday:
var d = new Date(2012, 0, 20);
//override Date constructor so all newly constructed dates return this Friday
Date = function(){return d;};
var now = new Date();
var another = new Date();
console.log(now);
another.setDate(13);
now = new Date()
console.log(now);
And the result is:
Date {Fri Jan 20 2012 00:00:00 GMT+0700 (SE Asia Standard Time)}
Date {Fri Jan 13 2012 00:00:00 GMT+0700 (SE Asia Standard Time)}
So, what goes wrong?
You already overridden core Date function by
Date = function(){return d;}; // after construction, all date will be d (2012-01-20)
var now = new Date(); // you instantiate a date, but actually now variable is d (2012-01-20)
var another = new Date(); // you instantiate a date, but another is still d (2012-01-20)
another.setDate(13); // change another date to 13 is to change now to 13 (because now and another is still one d)
now = new Date() // still d
console.log(now); // print out now (2012-01-13)
So, you overrides core Date function by a function that causes all date use the same (just one) instance, which is d (2012-01-20). Change any dates affect others.
This is working for me.
I.E how to return process time 1 minute back
Date = class extends Date{
constructor(options) {
if (options) {
super(options);
} else {
super(Date.now() - 1000 * 60);
}
}
};
Give this a shot.
var d = new Date(2012, 0, 20);
// undefine date so that it will only return what your function returns
Date = undefined;
Date = function(){return d;}
Modifying the prototype to point to your object should do the trick.
I believe the strange behavior you were experiencing earlier was that privately Date holds some notion of time, and since the prototype points to that internal clock, you were getting random times.
Alex Stanovsky's answer almost did it for me but this modification made the constructor work like before when given parameters.
Date = class extends Date {
constructor(...options) {
if (options.length) {
super(...options);
} else {
super(2019, 2, 11, 19, 19);
}
}
};
I used the below to enforce UTC dates
var _f = function(item) {
Date.prototype["get" + item] = Date.prototype["getUTC" + item];
Date.prototype["set" + item] = Date.prototype["setUTC" + item];
}
var _d = ['Milliseconds', 'Seconds', 'Minutes', 'Hours', 'Date', 'Month', 'FullYear', 'Year', 'Day'];
_d.forEach(_f);
Date = class extends Date {
constructor(...options) {
if (options.length == 1 && options[0].constructor == Date) {
super(options[0]);
} else if (options.length > 0) {
super(Date.UTC(...options));
} else {
super(Date.UTC());
}
}
};

Categories

Resources