Get next occurrence of a weekday if not found in desired week - javascript

How can I come up with an algorithm to find out the very next occurrence of a weekday if not found in the desired week. For example following is the screenshot of the calendar. There is no Tuesday in first week of April. I need an idea how can I go for the next Tuesday in the next week if not present in the given week?
Below is my algorithm which is working fine in getting any week's selected weekday. I just want to add two conditions in it to iterate back and forth in the case when weekday is not present in the given week.
for(var ind=0; ind<=between.length; ind++){
if (new Date(between[ind]).getMonthWeek() === baseDtWk && new Date(between[ind]).getDay() === baseDtD) {
datesToBeMarked.push(between[ind]);
console.log(" :Date: " + between[ind] + " :Week: " + new Date(between[ind]).getMonthWeek());
console.log("Date entered : " + new Date(between[ind]));
}
}
In above code baseDtWk & baseDtD contains the week and day.
Week is an integer from 1 to 5.
Day is an integer from 0 to 6 representing weekday from sun to sat.
for-loop iterates over all the array elements & push the elements into another array which has same week and weekday in a month. So ideally it is fulfilling the purpose in happy scenario, where every time weekday is available. Unlike the above case. Any ideas, guidance will be highly appreciable. Thanks.

By looking at your code it looks like you already have the structure in place just need to know how to utilize it.
I'm going to slightly modify your if condition as shown below.
for(var ind=0; ind<=between.length; ind++){
var thisDt = new Date(between[ind]);
if (thisDt.getMonthWeek() === baseDtWk && thisDt.getDay() === baseDtD) {
datesToBeMarked.push(thisDt);
console.log(" :Date: " + between[ind] + " :Week: " + thisDt.getMonthWeek());
console.log("Date entered : " + new Date(between[ind]));
}
}
Just by adding a var thisDt = new Date(between[ind]) you can get much cleaner code than before.
1. Now look at your code carefully you are already scanning each date by its week and weekday in your if-condition. And qualified element goes to datesToBeMarked[] array.
2. You need to introduce another if-condition which will walk through the between[] array and will scan every base day (You call it base which is the first element in your between[] array). Now the if-condition will look like as below.
for(var ind=0; ind<=between.length; ind++){
var thisDt = new Date(between[ind]);
if (thisDt.getMonthWeek() === baseDtWk && thisDt.getDay() === baseDtD) {
datesToBeMarked.push(thisDt);
console.log(" :Date: " + between[ind] + " :Week: " + thisDt.getMonthWeek());
console.log("Date entered : " + new Date(between[ind]));
}else if(thisDt.getDay() === baseDtD && thisDt.getMonth()!==new Date(datesToBeMarked[ind-1]).getMonth()){
//some magic needs to be done here
}
}
3. What is happening above in the else-if? It is checking your already selected Tuesday with the next element. If it is coming in the same month then reject it. Otherwise let it come inside the if-condition to see the magical move. :)
4. Lastly here inside your else-if you need a function to be called which will find you the next occurrence of the Tuesday if it is not in place initially in the first week as shown in your picture above.
5. Function for finding the day will look like as written below. And you are all set hopefully.
Following function needs to be replaced inside your else-if with this comment //some magic needs to be done here.
function nthDay(nth, weekday, month, year) {
var nthDate = new Date(year, month + ((nth <= 0) ? 1 : 0), 1);
var dayofweek = nthDate.getDay();
var offset = weekday - dayofweek;
nthDate = new Date(year, month + ((nth <= 0) ? 1 : 0), nthDate.getDate() + (offset + (nth - (offset >= 0 ? 1 : 0)) * 7));
if (nthDate.getMonth() !== month) {
return false;
} else {
return nthDate;
}
}
6. Happy Coding :)

Related

Google Apps script - IN operator for minutes

I try to run a sequential code. First update should happen every 15 minutes, the second one always 3 minutes after the first one.
The code below runs every minute.
However, it never works in Google Apps Script. Any idea how to fix it?
I only came up with writing out the in clause to == and or. It does not look straight.
function update_per_1_min() {
var d = new Date();
var m = d.getMinutes();
var m = 16
if(m in [1.0,16.0,31.0,46.0]){
update_0()
} else if (m in [4,19,34,49]) {
update_1()
}
}
in checks whether the expression is a property of the object. Arrays have properties like 0 for the first index, 1 for the second index, etc:
const arr = ['foo', 'bar'];
console.log('foo' in arr);
console.log('0' in arr);
Properties are not the same thing as values, of course. It looks like you're trying to check whether the value is contained in the array, in which case you could use .includes (if you were able to use ES6), or indexOf for GAS:
function update_per_1_min() {
var d = new Date();
var m = d.getMinutes();
if([1,16,31,46].indexOf(m) !== -1){
update_0()
} else if ([4,19,34,49].indexOf(m) !== -1) {
update_1()
}
}
(note that trailing zeros after the . in numbers is meaningless - feel free to leave those out entirely)

difficulty with approach to allowing user to input time

Stuck on the thinking of this, a user can enter a time into a field in the formats listed below. The time in the end will be saved and formatted to xx:xx 12 hour. I'm allowing flexibility/laziness on the user's part rather than throw strict errors.
Formats Allowed
1 (1 digit)
11 (2 digits)
11 1(hours and min)
11 10(hours and mins)
1110(hours and mins, no space)
Problems
I need to somehow take the user's entered time
Add prefixed zeros where needed so i get (xx:xx)
Add ":" in between hours and mins
Why do I need specifically ":" inserted? I need to save hour and min into separate variables later but I need to reformat the time behind the scenes so that it's ALWAYS xx:xx, having it in a predictable format means I can use JavaScript to split it by the ":" and do what I need to from there.
I'm not looking for the straight answer so much as suggestions because I'm under the assumption i'll need regex.
http://jsfiddle.net/8dabu7d8/7/
var number = "11 11";
console.log(format(number));
function format(number) {
if (number.length == 1 ) {
return '0' + number + ':00'
}else if (number.length == 2) {
return number + ':00'
} else if (number.length == 3){
return number.substring(0, 2) + ':' + number.substring(2)
} else if (number.length == 4 || number.length == 5){
return number.substring(0, 2) + ':' + number.substring(2).trim()
}
}
Using the replace method, you could do something such as :
var myRegexp = /(\d{1,2})[ ]?(\d{0,2})/i;
var match = myRegexp.exec(yourString);
var result = match[1];
if(match[1].length == 1)
{
result = match[1].concat("0");
}
result = result.concat(":");
if(match[2].length != 2)
{
if(match[2].length == 0){
result = result.concat("00");
}
else{
result = result.concat(match[1].concat("0"));
}
}
My suggestion is to use a time picker which will solve all your overheads and the user experience will also be great.You have a enormous time picker controls available in java script.
here is a simple example
http://jonthornton.github.io/jquery-timepicker/
I feel better to use any of these time picker control.

Take value of variable and run it through array

I am in the process of building a calculator to determine how long a childs colic is going to last.
I have the calculator working correctly just need it to take the value it gets and run it through the array and match the next closest value to the value shown and then reference it to its associated week.
So for instance if you select week 2 and then week 5 the calculation returns childs colic will end in .5614399999999999 weeks. You would then run the .5614 through the wessel_data array and find that .5614 falls in between week 6 and 7. I would then take the next closest week which is week 7 and show that instead of the .5614. So it should say childs colic will end in .64 weeks. Now that it has found the .64 I want it to output the associated weeks so that it would say childs colic will end in 7 weeks.
This is what I have written to find the next associated value but cant get it to work.
function closest (num, wessel_data) {
var curr = wessel_data[0];
var diff = Math.abs (num - curr);
for (var val = 0; val < wessel_data.length; val++) {
var newdiff = Math.abs (num - wessel_data[val]);
if (newdiff < diff) {
diff = newdiff;
curr = wessel_data[val + 1];
}
}
return curr;
}
I also have a fiddle so you can see what I am talking about.
Fiddle
I think you want the index of the wessel_data, not the data itself. That is just for comparing. So in this function set curr = val + 1. Not wessel_data[val + 1].
You aren't using this function at all in your fiddle so it is hard to tell what exactly you are doing.
My advice is to think of what values you want returned given inputs and work backward from there.

How to Sum up last 12 month amounts in javascript dynamically

I need to write a code regarding last 12 months calculation every next month so that when a user enters the value in the current month or in next month he should get the result
here how the calculation goes
CA (jan 14) = (Avg of B.Y. 2001=100 for the past 12 months - 115.76)*100/115.76
CA (jan 14)=( 232.66-115.76)*100/115.76=100.009
so every month if some body enters it we should get the value by the above calculation.
I tried with some sort of coding in JavaScript please checkout in this link
http://jsfiddle.net/kundansingh/SLC5F/
B.Y. 2001=100 = value will be enter by user
Total of 12 Months = total value of last 11 months and current month so 12 months
% Increase over 115.763 = 232.66-115.76
App. CA = ( 232.66-115.76)*100/115.76
i need dynamically for every month if input for next month value also it should show the result... what i have created is for one month ..please help me to sort the issue
In this case I'd really recommend using jQuery to make your life a lot easier, especially since you're going to want to do at least one for loop, if not two.
You need to loop through each row, get the previous 11 values, then do your calculations.
In your jsFiddle, the following code should work. I have edited your jsFiddle accordingly: http://jsfiddle.net/SLC5F/1/
$('tr', '#order-table').each(function() {
var total = 0;
var $rows = $(this).prevAll();
// return if we don't have enough rows
// probably better to just add a class to the active rows instead,
// but it's not my job to format your code.
if ( $rows.length < 13) return;
$rows = $rows.slice(0, 11);
// again, would be better to add a class to active inputs instead of using
// a not() filter. you can do this yourself.
total += parseFloat( $(this).find('input').not('.row-total-input, [readonly]').val() );
$rows.each(function() {
total += parseFloat( $(this).find('input').not('.row-total-input').val() );
});
// return if total isn't a number
if ( isNaN(total) ) return;
var monthly_average = total / 12;
// again, would be better to add classes to these TDs instead of using eq()
// make sure you do this before using this script in a live application.
$('td', this).eq(2).text(total);
$('td', this).eq(3).text(Math.round(monthly_average * 100) / 100);
$('td', this).eq(4).text(Math.round(( monthly_average - 115.763 ) * 100 / 115.764 * 100) / 100);
});

Regex inside TableSorter parser deletes indices where the same regex works correctly in a separate console function

Using Jquery TableSorter, I am creating a custom parser to sort elapsed time <td>s that contain "'#' year(s) * '#' month(s)". When I use the function
$('.techtable td:nth-child(6)').each(function(){
// console.log($(this));
var that = $(this).text();
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec($(this).text());
console.log(match);
});
from the command line, each index contains an array of length 5, looking like this:
["7 months", "7", "months", undefined, undefined]
to this:
["3 years 3 months", "3", "years", "3", "months"]
depending on whether or not the elapsed time has just a month or year element, and then the other. To parse the text, I use regex to gather each element, and then use JS to test whether there are multiple elements or not, and if 1 element only, then wheher it begins with "y" or "m", and return the number of months, so the parser can sort the <td>s by number of months in integer form.
The parser passes in each element into the function as parameter "s". when i try regex on "s" directly, it is not returning an array of length 5, it is truncating it to 3 (whether or not I am running the line that truncates it if index 3 is typeof 'undefined'). When I use the console to directly use this function:
$('.techtable td:nth-child(6)').each(function(){
// console.log($(this));
var that = $(this).text();
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec($(this).text());
if (typeof match[3] == 'undefined') {match.length = 3;};
console.log(match);
});
the regex returns the arrays properly, with the array truncated if it only has 1 element (year or month). Here is the code for the custom parser:
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec(s);
var order = [];
console.log(match);
if (typeof match[3] == 'undefined') {match.length = 3;};
// 1 element case:
// month
if (match.length = 3) {
if (match[2][0] == "m") {
order.push(match[1]);
}
// year
if (match[2][0] == "y") {
order.push(match[1]*12);
}
// both elements
} else {
order.push(match[1]*12 + match[3]);
}
s = order;
return s;
},
The fiddle is here. The Elapsed parser is second from the bottom of the JS panel. As you can see, since I can't get the months from the array (indices 4 and 5), I can not calculate the months, and thus the sorting only incorporates years, and the months are sorted by their original HTML placement. What am I missing? (I'm learning.... so direction is appreciated more than an fix, but I won't turn it down.)
Yes I realize the JS fiddle is loaded (first part is TableSorter, to maintain functionality for verification(click on headers to sort), but all you need to focus on is the last part of the code (reference the '//Table Sorter dateSorter' to see how a correct parser should look). The section '//Table Sorter elapsedSorter' is where my two attempts are, the first part is the working code I use in the console, and the seconde part is the parser, which is somehow deleting the last two indices in the array, thus loosing the month information to calculate.
Guess I'll have to add Regex, and a personal rating of 1, since I've wasted almost an entire day on this.
if (match.length = 3) {
You meant this?
if (match.length == 3) {
To help you further, when you write conditions with one constant and a variable, you can write them like this instead:
if (3 = match.length) {
This would now cause a JavaScript error instead of silently getting turned into an assignment that always yields true.
In JavaScript, 12 + '4' == '124', so you have to be careful with numbers and the + operator. In languages such as PHP you don't have this problem, because they have an operator for string concatenations ;-)
var myRegexp = /([\d]+) ([\w]+)(?: ([\d]+) ([\w]+))?/;
var match = myRegexp.exec(s);
var order = [];
if (typeof match[3] == 'undefined') {
if (match[2][0] == "m") {
order.push(parseInt(match[1]));
}
// year
if (match[2][0] == "y") {
order.push(parseInt(match[1])*12);
}
// both elements
} else {
order.push(parseInt(match[1])*12 + parseInt(match[3]));
}
s = order;
return s;
Btw use parseInt(x, 10) if you expect fields to have leading zeroes (which would otherwise result in 0 being returned). Thanks fudgey!

Categories