I have my dates converted to moment.js, and now I want to compare it with another date ('now' in this case).
Just a plain compare with a date object seems to be a lot faster than using moment.js isAfter function.
Will this simple compare work in all locales?
Am I missing something here?
Is there a very specific reason why isAfter seems to create a new moment object instead of taking a shortcut when it's a Date object?
All my dates are in UTC.
function executeTests() {
isAfterTest();
compareTest();
}
function isAfterTest() {
console.time('isAfterTest');
var now = new Date();
var dateOfBirth = moment('2000-01-01');
for (var i = 0; i < 50000; i++) {
var x = dateOfBirth.isAfter(now);
}
console.timeEnd('isAfterTest');
}
function compareTest() {
console.time('compareTest');
var now = new Date();
var dateOfBirth = moment('2000-01-01');
for (var i = 0; i < 50000; i++) {
var x = dateOfBirth > now;
}
console.timeEnd('compareTest');
}
<script src="http://cdnjs.cloudflare.com/ajax/libs/moment.js/2.7.0/moment-with-langs.js"></script>
<button onclick="executeTests();">Run Test</button>
Results:
isAfterTest: 3754.000ms (index):32
compareTest: 24.000ms
See: http://jsfiddle.net/t4grs0p7/2/
Looking at the documentation http://momentjs.com/docs/ the isAfter method accepts different types of Date format:
moment().isAfter(Moment|String|Number|Date|Array);
This means it needs to do type checking and then convert it to a date object before running the calculation.
One way you could reduce this impact would be to pass in a Moment object as the comparison date:
function isAfterTest() {
console.time('isAfterTest');
var now = moment();
var dateOfBirth = moment('2000-01-01');
for (var i = 0; i < 50000; i++) {
var x = dateOfBirth.isAfter(now);
}
console.timeEnd('isAfterTest');
}
I created a fiddle to compare, but that doesn't seem to improve it much at all:
http://jsfiddle.net/kmturley/t4grs0p7/7/
Looking at your version I believe you should be using valueOf() method to compare the values:
window.compareTest2 = function() {
console.time('compareTest2');
var now = moment().valueOf();
var dateOfBirth = moment('2000-01-01').valueOf();
for ( var i = 0; i < 50000; i++ )
var x = dateOfBirth > now;
console.timeEnd('compareTest2');
}
Here is a working example:
http://jsfiddle.net/kmturley/t4grs0p7/8/
Related
I cant compare javascript object to string, I'm using Google Sheets JavaScript. Data is date but when I checked it with typeof it indicated object. Here is my code:
function myFunction() {
SpreadsheetApp.getUi()
.alert('Running My Function');
}
function myFunction() {
var doc = SpreadsheetApp.getActiveSpreadsheet();
var sheet = doc.getSheetByName("Taulukko1");
var values = sheet.getRange("A1:K28").getValues();
var row_del = new Array();
for(var i=0;i<values.length; i++)
{
if(new Date(values[i][7]).getDate() == new Date('2020-09-17').getDate()){
row_del.push(i);
}
}
for (var i = row_del.length - 1; i>=0; i--) {
sheet.deleteRow(row_del[i]); }
}
A date is an object.
However, you cannot compare dates directly.
To compare dates, the easiest is to convert them to milliseconds.
Sample:
if(new Date(values[i][7]).getTime() == new Date('2020-09-17').getTime()){
// do something
}
note the correct formatting.
References:
new Date()
getTime()
I have the following simplified (javascript) object, of which properties are dates (in string fomat):
Given a random startdate and enddate within the range of dates in the object, how to code (efficiently) the calculation - say accumulate- of the values within this range? As an example, for the following code the calculation result should be 12 (3+4+5) for the given startdate and enddate.
var startdate = '2014-01-03';
var enddate = '2014-01-05'
var obj = {};
obj['2014-01-02'] = '2';
obj['2014-01-03'] = '3';
obj['2014-01-04'] = '4';
obj['2014-01-05'] = '5';
obj['2014-01-06'] = '6';
You can just loop through the properties of the object, doing a comparison, and adding.
var startdate = '2014-01-04';
var enddate = '2014-01-05';
var arr = {};
arr['2014-01-02'] = '2';
arr['2014-01-03'] = '3';
arr['2014-01-04'] = '4';
arr['2014-01-05'] = '5';
arr['2014-01-06'] = '6';
var total = 0;
for(var p in arr) {
if(arr.hasOwnProperty(p)) {
if(new Date(p) >= new Date(startdate) && new Date(p) <= new Date(enddate)) {
total += parseInt(arr[p], 10);
}
}
}
console.log(total);
Sample http://jsbin.com/imUdewaJ/1/edit
I'm sure there is a better way to do this, but I don't know how due to having to parse the date object out for comparison.
--Edit added in the hasOwnProperty check from comments below
When doing stuff with dates, you might want to use thirdparty tools to handle browser compatibility. Momentjs is a good one for dates.
solution with momentjs:
var startdate = moment('2014-01-03');
var enddate = moment('2014-01-05');
var obj = {};
obj['2014-01-02'] = '2';
obj['2014-01-03'] = '3';
obj['2014-01-04'] = '4';
obj['2014-01-05'] = '5';
obj['2014-01-06'] = '6';
var strDate;
var total = 0;
for (strDate in obj) {
if (obj.hasOwnProperty(strDate)) {
var date = moment(strDate)
if (date.diff(startdate, 'days')>=0 && date.diff(enddate, 'days')<=0) {
total += parseInt(obj[strDate], 10);
}
}
}
console.log(total);
It's possible that some browsers won't support date1 > date2, so it might be better to also use getTime().
function getDate(date) {
return new Date(date).getTime();
}
function getTotal(start, end) {
var total = 0;
for (var k in obj) {
var current = getDate(k);
if (current >= start && current <= end) {
total += parseInt(obj[k], 10);
}
}
return total;
}
var start = getDate(startdate);
var end = getDate(enddate);
console.log(getTotal(start, end)); // 12
Let's say I have an array of N dates:
var dates = ['2013-01-01', '2013-01-02', '2013-01-05' ...]
What is the quickest way to find all the missing dates between the first date and the last? (let's assume that the dates are sorted from earliest to latest).
The gap is not consistent and could be at any size.
I rather not use any libraries, just pure javascript.
Generally if you have two sorted arrays and want to find the items in one missing from the other you would iterate over both in paralel. My solution is similar to that one, but uses a generator over the date array:
function DateIterator(date){
this.current = date;
}
DateIterator.prototype.next = function() {
this.current.setDate(this.current.getDate() + 1);
return this.current.getFullYear() + '-' +
(this.current.getMonth()+1) + '-' +
this.current.getDate();
};
var dates = ['2013-1-1', '2013-1-2', '2013-1-5' ,'2013-2-2'];
var di = new DateIterator(new Date(dates[0]));
var date, missing = [];
for (var i=1; i<dates.length; i++) {
while ((date = di.next()) !== dates[i]) {
missing.push(date);
}
}
console.log(missing);
Note that the check for dates is made by comparing the string values. The dates returned by next are not 0-padded so a comparison between 2013-01-01 and 2013-1-1 would fail. This can be solved by making a smarter comparison function, but i consider it beyond the scope of the question.
I would do a date diff, and generate new dates for any missing ones, like this:
var dates = [new Date(2013,1,1), new Date(2013,1,2), new Date(2013,1,5)];
var missingDates = [];
for (var i = 1; i < dates.length; i++)
{
var daysDiff = ((dates[i] - dates[i - 1]) / 86400000) - 1;
for (var j = 1; j <= daysDiff; j++)
{
var missingDate = new Date(dates[i - 1]);
missingDate.setDate(dates[i - 1].getDate() + j);
missingDates.push(missingDate);
}
}
console.log(missingDates);
JSFiddle
I am having a datatable return a number of Dates received - they are coming back in the format below(will always take this format):
/Date(1362045881257)/
how can I easily strip this to just the epoch digits so I can then convert into a readable date.
I have tried the following so far but it is not working as expected. So the first thing I was trying to remove was just the ( ) - then I was going to do another .replace to remove the / / and then remove the Date which would leave me with just the digits.
success: function (msg) {
for (var i = 0; i < msg.aaData.length; i++) {
var date = msg.aaData[i].DateReceived;
date.replace(/\(|\)/g, '');
alert(date);
}
fnCallback(msg);
},
success: function (msg) {
for (var i = 0; i < msg.aaData.length; i++) {
// toString() below might be redundant!
var date = msg.aaData[i].DateReceived.toString();
var reg = /[^0-9]/g;
var epoch = date.replace(reg, ''));
alert(epoch);
}
fnCallback(msg);
},
First of all thank you for the efforts made in this site. As an individual and a beginner i have learnt from my errors made. Thanks for all who have contributed & extended their support.
Thanks for this.
Here is a small program written which is not working (no output)seen , i have tried it in many ways but in vain. please help me to find a solution for this.
the aim of this program was to filter the data from 4 sheets and paste into current sheet (master). this filter is based on date values.
Conditions of dates are taken from the master sheet in columns in (b2 & d2)dates. this are to be filtered out based in column no.18 which has dates in client sheets.
function myFunction3() {
var source = ['0AjkkHlm3kCphdGhSWnlxWmFsakZ2aFhMSHl6SlF3M1E',
'0AjkkHlm3kCphdHY2aXpjTVJEMlFRYVBST0ZPYzNwRFE',
'0AjkkHlm3kCphdEc5ZHFpeHVlc241SlFKWGJDeXFKLXc',
'0AjkkHlm3kCphdG9WVjVRRnQ3RlFlcllhd1JGallXVmc'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get start date from sheet
var sDate = ss.getSheetByName('123').getRange("B2").getValue();
// get end date from sheet
var eDate = ss.getSheetByName('123').getRange("D2").getValue();
// days between
var Dura = ss.getSheetByName('123').getRange("E1").getValue();
var codes = new Array();
for (var k = 0; k < Dura; k++){
var d = new Date(sDate);
d.setDate(d.getDate()+ k);
codes[k] = d;
}
var numCodes = codes.length;
var copied = [];
for (var k = 0; k < numCodes; k++) {
copied[k] = [];
}
//get data from external sheets for comparision
for (var i = 0; i < source.length; i++) {
var tempCopy = SpreadsheetApp.openById(source[i]).getSheetByName('Footfall-Format').getDataRange().getValues();
// comparision starts
for (var j = 0; j < tempCopy.length; j++) {
var codeIndex = codes.indexOf(tempCopy[j][5]);
if (codeIndex > -1) copied[codeIndex].push(tempCopy[j]);
}
}
var sheets = SpreadsheetApp.getActive().getSheets();
for (var m = 0; m < numCodes; m++) {
if (copied[m][0] != undefined) {
var gensheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('123');
gensheet.getRange(5, 1, 1500, 18).clear({contentsOnly:true});
gensheet.getRange(5, 1, copied[m].length, copied[m][0].length).setValues(copied[m]);
}
}
}
The fundamental problem is that you are comparing objects for equality - in this case, you're comparing Date objects. Even when the date represented by two of these objects is the same, the object comparison comes up false unless you're actually referencing the same object. You can read more about this in Compare two dates with JavaScript.
Here's a simple change to your script, using toDateString(), that will ensure your codes[] array contains string values that can be compared with values in tempCopy[j][5].
function myFunction3() {
var source = ['0AjkkHlm3kCphdGhSWnlxWmFsakZ2aFhMSHl6SlF3M1E',
'0AjkkHlm3kCphdHY2aXpjTVJEMlFRYVBST0ZPYzNwRFE',
'0AjkkHlm3kCphdEc5ZHFpeHVlc241SlFKWGJDeXFKLXc',
'0AjkkHlm3kCphdG9WVjVRRnQ3RlFlcllhd1JGallXVmc'];
var ss = SpreadsheetApp.getActiveSpreadsheet();
// get start date from sheet
var sDate = ss.getSheetByName('123').getRange("B2").getValue();
// get end date from sheet
var eDate = ss.getSheetByName('123').getRange("D2").getValue();
// days between
var Dura = ss.getSheetByName('123').getRange("E1").getValue();
var codes = new Array();
for (var k = 0; k < Dura; k++){
var d = new Date(sDate);
d.setDate(d.getDate()+ k);
codes[k] = d.toDateString(); //***** Make array of Strings, not Dates
}
var numCodes = codes.length;
var copied = [];
for (var k = 0; k < numCodes; k++) {
copied[k] = [];
}
//get data from external sheets for comparision
for (var i = 0; i < source.length; i++) {
var tempCopy = SpreadsheetApp.openById(source[i]).getSheetByName('Footfall-Format').getDataRange().getValues();
// comparision starts
for (var j = 4; j < tempCopy.length; j++) { // start at 4 to skip headers
if (typeof tempCopy[j][5] != "object") break; // skips strings, but could improve
// Search for String match of date from input record
var codeIndex = codes.indexOf(tempCopy[j][5].toDateString());
if (codeIndex > -1) copied[codeIndex].push(tempCopy[j]);
}
}
// This part has bugs... each day overwrites the previous
var sheets = SpreadsheetApp.getActive().getSheets();
for (var m = 0; m < numCodes; m++) {
if (copied[m][0] != undefined) {
var gensheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('123');
gensheet.getRange(5, 1, 1500, 18).clear({contentsOnly:true});
gensheet.getRange(5, 1, copied[m].length, copied[m][0].length).setValues(copied[m]);
}
}
}
As #Serge points out, there are other problems in this code.
d.getDate()+ k does not handle month-end, so you need to do that yourself.
The last part of your script that handles the output via setValues() needs to be debugged. As it is, each day overwrites the previous day's values from the copied[] array. I'm not sure what requirement you were trying to meet with this, so I left it alone, but it needs attention.