Checking MomentJS data toString not evaluating properly in if check - javascript

I am trying to create a function to create an array of the next two weeks of days that are not Friday, Saturday, or Sunday. moment().isoWeekday().toString() returns a number 1-7 depending on the day. I have an if statement checking to see if each day matches 5, 6, or 7, but they all return true no matter the day. I'm not sure what I'm doing wrong. Please advise.
for (let i = 1; i < 14; i++) {
if (moment().add(i, 'days').isoWeekday().toString() !== '5' ||
moment().add(i, 'days').isoWeekday().toString() !== '6' ||
moment().add(i, 'days').isoWeekday().toString() !== '7') {
console.log(moment().add(i, 'days').isoWeekday().toString())
dayArray.push(moment().add(i, 'days').toString());
}
}

The error seems to come from you condition, you use OR (||) instead AND (&&)
for (let i = 1; i < 14; i++) {
if (moment().add(i, 'days').isoWeekday().toString() !== '5' &&
moment().add(i, 'days').isoWeekday().toString() !== '6' &&
moment().add(i, 'days').isoWeekday().toString() !== '7') {
console.log(moment().add(i, 'days').isoWeekday().toString())
dayArray.push(moment().add(i, 'days').toString());
}
}

Related

Why is this if statement not affected by my input?

I want to build an algorithm who convert AM/PM to the 24hours format. It's not finished, but the code I have so far is behaving strangely.
When I give the input "25:05:45PM", it should enter the first branch of the first if statement, but should not enter the second if statement. I've checked the condition, and it's definitely false. My brain is melting.
Here is the code :
function conversionTime(s) {
if (s.includes('PM')) {
let temp = s.slice(0, 8).split(':');
if (temp[0] >= 01 && temp[0] <= 12); {
temp[0] = Number(temp[0]) + 12;
return temp.join(':')
}
} else if (s.includes('AM')) {
let temp2 = s.slice(0, 8).split(':');
return temp2
}
}
console.log(conversionTime("25:05:45PM"))
Gotcha.
if (temp[0] >= 01 && temp[0] <= 12);
This semicolon is the culprit! It's saying "the if statement is over, no need to do anything", so your code is being interpreted like:
if (temp[0] >= 01 && temp[0] <= 12);
{
temp[0] = Number(temp[0]) + 12;
return temp.join(':');
}
The code in the block will always run. This feature exists so you can make full use of let's scoping:
let x = "outside";
console.log(x);
{
let x = "inside";
console.log(x);
}
console.log(x);
Well, really it exists because that's how C works – it predates the let statement – but that's what it's useful for these days.
I Will do that this way..
function conversionTime(timeAPM)
{
let [h,m,s,apm] = timeAPM.match(/(\d+)|(\w+)/g);
if (timeAPM !== `${h}:${m}:${s}${apm}`
|| isNaN(h) || isNaN(m) || isNaN(s)
|| (apm !== 'AM' && apm !== 'PM')
) return undefined;
if (apm === 'PM' && h <= 12 ) h = +h +12;
return `${h}:${m}:${s}`;
}
console.log(conversionTime("25:05:45PM"))
I don't know if it's intentional or not on his part, but the PO's code also returns undefined. Apart from his attachment to the AM/PM labels, the OP gives no explanation on the validity of the entry.
So this second version is content to check that there are indeed 3 numerical values, separate by :, and directly followed by AM or PM.
the number of digits of these numbers is unknown : His test uses an hour = 25 while it is an AM/PM presentation. So why not seconds or minutes expressed with 40 digits...
I'm not claiming my regex is the best in the universe.
I could also have added in my code:
console.log(conversionTime("10:31:25BAM")) // -> undefined
console.log(conversionTime("1:3:5abc")) // -> undefined
console.log(conversionTime("1:3zzzz")) // -> undefined
console.log(conversionTime("a:10:15PM")) // -> undefined
console.log(conversionTime("285::4875PM")) // -> undefined
// or more absurd:
console.log(conversionTime("285:1505:4875PM")) // -> 285:1505:4875

Javascript - Get a date from any kind of string

I would like to know if there is a way (I hope there is one, or I am in trouble :p), to find a date in any kind of string.
Here are some examples to make you understand what I am looking for :
var string1 = 'blabla-test-20140215.dat'
I would need to have access to '20140215'
var string2 = 'blabla_Test.20141212'
I would need to have access to '20141212'
Well, I would like to be able to find a date in a format yyyymmdd in a string, no matter the string.
Thank you if you have any clue, I haven't found anything on internet yet.
EDIT :
There can be other numbers in the string, but always less than 8.
for instance :
var string3 = 'blabla-2526-20141212'
The date I am looking for is always separated from other numbers. I can't have :
var string4 = 'blabla-252620141212'
I just want to find the numbers representing the date (in a format yyyymmdd, for instance in string3 I want 20141212, which refers to : 12/12/2014)
I'm note sure, but if your string contains digits only for date, you can use RexEx ?
may be like this :
var regex = /[0-9]+/;
var string1 ="blabla-test-20140215.dat";
var found = regex.exec(string1);
alert('Found: ' + found);
It is simple enough to extract a sequence of eight numbers from a string with regex, just use something like the following:
var dateString = (/\d{8}/.exec(string) || [])[0];
This will find the first eight-character-long string of numbers in a given string. If no such sequence exists, it will be undefined. You can then use it to create a Date object if necessary.
You should use Regex for this.
re = /(\d{4})(\d{2})(\d{2})/g //create a regex that matches: 4 digits followed by 2 digits followed by 2 digits
///// yyyy mm dd
result = re.exec(string1) //execute the regex
// now, access the different capture groups according to their indexes
console.log(result[1]) // yyyy
console.log(result[2]) // mm
console.log(result[3]) // dd
This solution will check for valid dates (not just any 8 arbitrary numbers):
function hasDate(input) {
var matches = input.match(/(\d{4})(\d{2})(\d{2})/),
indexOf = function (elem, arr) {
var len = arr.length, i;
for (i = 0; i < len; i++) {
if (arr[i] === elem) {
return i;
}
}
return -1;
},
months31 = [1, 3, 5, 7, 8, 10, 12],
idx, isLeapYear,
year, month, day;
if (matches) {
year = parseInt(matches[1]);
month = parseInt(matches[2]);
day = parseInt(matches[3]);
//Check invalid dates from the start
if (month < 1 || month > 12) {
return false;
}
else if (day < 1 || day > 31) {
return false;
}
idx = indexOf(month, months31);
isLeapYear = ((year % 4 === 0) && (year % 100 !== 0)) || (year % 400 === 0);
//Month has 31 days, we are good
if (idx >= 0) {
return true;
}
//Feb - check for leap year
else if (month === 2 && (day <= 28 || (isLeapYear && day <= 29))) {
return true;
}
//All other months
else if (month !== 2 && day <= 30) {
return true;
}
}
//If we got this far, its a bad date
return false;
}
//return true
hasDate('blabla_Test.20141212');
//return false
hasDate('blabla_Test.20140229');
//return true
hasDate('blah_20140228');
//return true
hasDate('blah_20000229');

How to check if a string is a natural number?

In javascript, how can you check if a string is a natural number (including zeros)?
Thanks
Examples:
'0' // ok
'1' // ok
'-1' // not ok
'-1.1' // not ok
'1.1' // not ok
'abc' // not ok
Here is my solution:
function isNaturalNumber(n) {
n = n.toString(); // force the value incase it is not
var n1 = Math.abs(n),
n2 = parseInt(n, 10);
return !isNaN(n1) && n2 === n1 && n1.toString() === n;
}
Here is the demo:
var tests = [
'0',
'1',
'-1',
'-1.1',
'1.1',
'12abc123',
'+42',
'0xFF',
'5e3'
];
function isNaturalNumber(n) {
n = n.toString(); // force the value incase it is not
var n1 = Math.abs(n),
n2 = parseInt(n, 10);
return !isNaN(n1) && n2 === n1 && n1.toString() === n;
}
console.log(tests.map(isNaturalNumber));
here is the output:
[true, true, false, false, false, false, false, false, false]
DEMO: http://jsfiddle.net/rlemon/zN6j3/1
Note: this is not a true natural number, however I understood it that the OP did not want a real natural number. Here is the solution for real natural numbers:
function nat(n) {
return n >= 0 && Math.floor(n) === +n;
}
http://jsfiddle.net/KJcKJ/
provided by #BenjaminGruenbaum
Use a regular expression
function isNaturalNumber (str) {
var pattern = /^(0|([1-9]\d*))$/;
return pattern.test(str);
}
The function will return either true or false so you can do a check based on that.
if(isNaturalNumber(number)){
// Do something if the number is natural
}else{
// Do something if it's not natural
}
Source: http://www.codingforums.com/showthread.php?t=148668
If you have a regex phobia, you could do something like this:
function is_natural(s) {
var n = parseInt(s, 10);
return n >= 0 && n.toString() === s;
}
And some tests:
> is_natural('2')
true
> is_natural('2x')
false
> is_natural('2.0')
false
> is_natural('NaN')
false
> is_natural('0')
true
> is_natural(' 2')
false
You can do if(num.match(/^\d+$/)){ alert(num) }
You could use
var inN = !!(+v === Math.abs(~~v) && v.length);
The last test ensures '' gives false.
Note that it wouldn't work with very big numbers (like 1e14)
You can check for int with regexp:
var intRegex = /^\d+$/;
if(intRegex.test(someNumber)) {
alert('Natural');
}
function isNatural(num){
var intNum = parseInt(num);
var floatNum = parseFloat(num);
return (intNum == floatNum) && intNum >=0;
}
Number() parses string input accurately. ("12basdf" is NaN, "+42" is 42, etc.). Use that to check and see if it's a number at all. From there, just do a couple checks to make sure that the input meets the rest of your criteria.
function isNatural(n) {
if(/\./.test(n)) return false; //delete this line if you want n.0 to be true
var num = Number(n);
if(!num && num !== 0) return false;
if(num < 0) return false;
if(num != parseInt(num)) return false; //checks for any decimal digits
return true;
}
function isNatural(n){
return Math.abs(parseInt(+n)) -n === 0;
}
This returns false for '1 dog', '-1', '' or '1.1', and returns true
for non-negative integers or their strings, including '1.2345e12',
and not '1.2345e3'.
I know this thread is a bit old but I believe I've found the most accurate solution thus far:
function isNat(n) { // A natural number is...
return n != null // ...a defined value,
&& n >= 0 // ...nonnegative,
&& n != Infinity // ...finite,
&& typeof n !== 'boolean' // ...not a boolean,
&& !(n instanceof Array) // ...not an array,
&& !(n instanceof Date) // ...not a date,
&& Math.floor(n) === +n; // ...and whole.
}
My solution is basically an evolution of the contribution made by #BenjaminGruenbaum.
To back up my claim of accuracy I've greatly expanded upon the tests that #rlemon made and put every proposed solution including my own through them:
http://jsfiddle.net/icylace/qY3FS/1/
As expected some solutions are more accurate than others but mine is the only one that passes all the tests.
EDIT: I updated isNat() to rely less on duck typing and thus should be even more reliable.
This is how I check if a string is a natural number (including zeros!).
var str = '0' // ok
var str1 = '1' // ok
var str2 = '-1' // not ok
var str3 = '-1.1' // not ok
var str4 = '1.1' // not ok
var str5 = 'abc' // not ok
console.log("is str natural number (including zeros): ", Number.isInteger(Number(str)) && Number(str) >= 0)
console.log("is str1 natural number (including zeros): ", Number.isInteger(Number(str1)) && Number(str1) >= 0)
console.log("is str2 natural number (including zeros): ", Number.isInteger(Number(str2)) && Number(str2) >= 0)
console.log("is str3 natural number (including zeros): ", Number.isInteger(Number(str3)) && Number(str3) >= 0)
console.log("is str4 natural number (including zeros): ", Number.isInteger(Number(str4)) && Number(str4) >= 0)
console.log("is str5 natural number (including zeros): ", Number.isInteger(Number(str5)) && Number(str5) >= 0)
const func = (number) => {
return Math.floor(number) === number
}
Convert the string to a number and then check:
function isNatural( s ) {
var n = +s;
return !isNaN(n) && n >= 0 && n === Math.floor(n);
}
function isNatural(number){
var regex=/^\d*$/;
return regex.test( number );
}
function isNatural(n) {
return Number(n) >= 0 && Number(n) % 1 === 0;
}
Why not simply use modulo?
if(num % 1 !== 0) return false;
Use /^\d+$/ will match 000.
so use /^[1-9]\d*$|^0$/ match positive integer or 0 will be right.

Is there a more compact way of checking if a number is within a range?

I want to be able to test whether a value is within a number range. This is my current code:
if ((year < 2099) && (year > 1990)){
return 'good stuff';
}
Is there a simpler way to do this? For example, is there something like this?
if (1990 < year < 2099){
return 'good stuff';
}
In many languages, the second way will be evaluated from left to right incorrectly with regard to what you want.
In C, for instance, 1990 < year will evaluate to 0 or 1, which then becomes 1 < 2099, which is always true, of course.
Javascript is a quite similar to C: 1990 < year returns true or false, and those boolean expressions seem to numerically compare equal to 0 and 1 respectively.
But in C#, it won't even compile, giving you the error:
error CS0019: Operator '<' cannot be applied to operands of type 'bool' and 'int'
You get a similar error from Ruby, while Haskell tells you that you cannot use < twice in the same infix expression.
Off the top of my head, Python is the only language that I'm sure handles the "between" setup that way:
>>> year = 5
>>> 1990 < year < 2099
False
>>> year = 2000
>>> 1990 < year < 2099
True
The bottom line is that the first way (x < y && y < z) is always your safest bet.
You could make your own method:
// jquery
$(function() {
var myNumber = 100;
try {
if (myNumber.isBetween(50, 150))
alert(myNumber + " is between 50 and 100.");
else
alert(myNumber + " is not between 50 and 100.");
} catch (e) {
alert(e.message());
}
});
// js prototype
if (typeof(Number.prototype.isBetween) === "undefined") {
Number.prototype.isBetween = function(min, max, notBoundaries) {
var between = false;
if (notBoundaries) {
if ((this < max) && (this > min)) between = true;
alert('notBoundaries');
} else {
if ((this <= max) && (this >= min)) between = true;
alert('Boundaries');
}
alert('here');
return between;
}
}
hope this helps.
Max
The fast and simple way to make this is to create a function like this:
function inRange(n, nStart, nEnd)
{
if(n>=nStart && n<=nEnd) return true;
else return false;
}
Then use that as follows:
inRange(500, 200, 1000) => this return true;
Or like this:
inRange(199, 200, 1000) => this return false;
If you don't like the boolean operator, you could always use nested if statements:
if (1990 < year)
{
if( year < 2099)
return 'good stuff';
}
From a similar solution here: http://indisnip.wordpress.com/2010/08/26/quicktip-check-if-a-number-is-between-two-numbers/
$.fn.between = function(a,b){
return (a < b ? this[0] >= a && this[0] <= b : this[0] >= b && this[0] <= a);
}

Problem sorting an array of objects by date & time in Javascript - null values allowed

I'm working with an array of objects in Javascript and need to sort them by date and time. Here's the setup:
place
title
date (optional)
time (optional)
Conceptually, the application allows users to create a list of places they're planning to go. The array of events is manually ordered at first, and users can optionally add date and time values to places. I'm providing an button to sort by date...places with null dates need to be placed at the bottom of the list.
Right now, it's behaving differently across browsers. Here's the code (assume I have a handle on the _places array and the _list object):
var _orderByDate = function (e) {
YUE.preventDefault(e); // yui
_places.sort(function (a, b) {
var dateA = new Date(a.date),
dateB = new Date(b.date);
if ((!dateA === null) && (dateB === null)) return 0; //they're both null and equal
else if ((dateA === null) && (dateB != null)) return -1; //move a downwards
else if ((dateA != null) && (dateB === null)) return 1; //move b downwards
else if ((dateA == dateB)) return (a.time > b.time) ? 1 : ((b.time > a.time) ? -1 : 0);
else return (dateA > dateB) ? 1 : ((dateB > dateA) ? -1 : 0);
});
_list.updatePlaces(_places);
}
If you recognize the sort code above, that's because I got the basics from another post, but I felt this one deserved it's own since it deals with dates...the other was just dealing with null values and text.
Anyway, in Chrome, the list seems to sort in a random order, and it keeps sorting differently every time I execute the _orderByDate function. In Safari, it sorts mostly correct the first time, but puts one null date place at the top of the list. In Firefox, nothing happens at all.
I'm a bit of a beginner, and I don't have a CS background at all, so I'm not adept at the basics like arrays, dates, times etc...and my debugging skills are limited to the Firebug console. No errors are being reported, so I really have no idea what's going wrong.
One thing to note, if I eliminate the date type from the function so it sorts the items as strings, it works correctly...but that means 1/10/2011 would sort before 1/9/2011, so I think I need the date type in there.
Any ideas what's going wrong? Is there a smarter way to do what I'm trying to do?
EDIT: Adding log values
First sort (Chrome):
08/01/2010
null
null
08/03/2010
null
null
null
null
7/01/2010
null
null
null
Second sort (Chrome):
08/01/2010
null
null
null
07/01/2010
null
null
null
null
null
8/03/2010
null
null
[See it in action]
_places.sort(function (a, b) {
var dateA = new Date(a.date + a.time), // merge the date & time
dateB = new Date(b.date + b.time); // depending on the format
if (!a.date && b.date) return 1;
else if (a.date && !b.date) return -1;
else if (dateA === dateB) return 0;
else return (dateA > dateB) ? 1 : (dateB > dateA ? -1 : 0);
});
You can simplify the sorting algorithm by a great deal if you pre-process your array so that it will have a numeric representation of the column you want to sort by.
Add a column to the table that contains the UTC equivalent of the dates for instance. Then you can safely sort the array by the UTC property, but you will still display the string value.
for (var idx in _places)
_places[idx].UTC = _places[idx].date ? new Date(_places[idx].date).UTC() : 0;
_places.sort(function(a, b)
{
return a.UTC > b.UTC ? 1 : a.UTC < b.UTC ? -1 : 0;
});
If you don't want to use the Date object (pre-1970 dates):
for (var idx in _places)
{
var row = _places[idx];
if (!row.date)
{
row.sortable = 0;
continue;
}
var date = row.date.split('/');
row.sortable = 10000 * parseInt(date[2]) + 100 * parseInt(date[0]) + parseInt(date[1]); // year, month, day
}
_places.sort(function(a, b)
{
return a.sortable > b.sortable ? 1 : a.sortable < b.sortable ? -1 : 0;
});
Of course this assumes that your dates will always have the same M/D/Y format.
Here's the above algorithm in action: http://jsfiddle.net/krNnn/
Ok, we got busy and built a rather complex function that works across all browsers. Some of the requirements we had were pretty special (dates in the distant past, need to sort null dates at the bottom, subsort by time). Here's what we did:
var _orderByDate = function(e) {
YUE.preventDefault(e);
_places.sort(function(a,b) {
var Ay, Am, Ad, By, Bm, Bd;
var Ah, Am, Bh, Bm;
var dateA = a.date.split("/");
if( !dateA.length || dateA.length != 3 || isNaN(dateA[0]) ||
isNaN(dateA[1]) || isNaN(dateA[2]) ) {
dateA = -1;
} else {
Ay = parseInt(dateA[2]);
Am = parseInt(dateA[0]);
Ad = parseInt(dateA[1]);
}
var dateB = b.date.split("/");
if( !dateB.length || dateB.length != 3 || isNaN(dateB[0]) ||
isNaN(dateB[1]) || isNaN(dateB[2]) ) {
dateB = -1;
} else {
By = parseInt(dateB[2]);
Bm = parseInt(dateB[0]);
Bd = parseInt(dateB[1]);
}
// null checks
if(dateA == -1 && dateB == -1) return 0;
if(dateA == -1 && dateB != -1) return 1;
if(dateA != -1 && dateB == -1) return -1;
// year check
if(Ay > By) return 1;
if(By > Ay) return -1;
// month check
if(Am > Bm) return 1;
if(Bm > Am) return -1;
// day check
if(Ad > Bd) return 1;
if(Bd > Ad) return -1;
var timeA = a.time.split(":");
if( !timeA.length || timeA.length != 2 || isNaN(timeA[0]) ) {
timeA = -1;
} else {
if( timeA[1].match(/am/) ) {
Ah = parseInt(timeA[0]);
Am = parseInt(timeA[1].match(/\d+/));
} else if( timeA[1].match(/pm/) ) {
Ah = parseInt((timeA[0] * 1) + 12);
Am = parseInt(timeA[1].match(/\d+/));
}
}
var timeB = b.time.split(":");
if( !timeB.length || timeB.length != 2 || isNaN(timeB[0]) ) {
timeB = -1;
} else {
if( timeB[1].match(/am/) ) {
Bh = parseInt(timeB[0]);
Bm = parseInt(timeB[1].match(/\d+/));
} else if( timeB[1].match(/pm/) ) {
Bh = parseInt((timeB[0] * 1) + 12);
Bm = parseInt(timeB[1].match(/\d+/));
}
}
// null time checks
if(timeA == -1 && timeB == -1) return 0;
if(timeA == -1 && timeB != -1) return 1;
if(timeA != -1 && timeB == -1) return -1;
// hour check
if(Ah > Bh) return 1;
if(Bh > Ah) return -1;
// minute check
if(Am > Bm) return 1;
if(Bm > Am) return -1;
return 0;
} );
_list.updatePlaces(_places);
}

Categories