Holiday Selection Script

I am not very good with Javascript. I found the Easter function and Googled how to setup the rest. This script is in a function node that I use for my holiday lights. It used to work but now that I have changed some things, it doesn't. I found a script from Stack Overflow that figures out when the non-fixed date holidays are that I would like to implement but I would like to have a working base while I try to figure out.

A 0 or 1 is sent into the function node as the payload. Any help is greatly appreciated.

const d = new Date();
var day = d.getDay();
var year = d.getFullYear();

function Easter(Y) {
    var C = Math.floor(Y/100);
    var N = Y - 19*Math.floor(Y/19);
    var K = Math.floor((C - 17)/25);
    var I = C - Math.floor(C/4) - Math.floor((C - K)/3) + 19*N + 15;
    I = I - 30*Math.floor((I/30));
    I = I - Math.floor(I/28)*(1 - Math.floor(I/28)*Math.floor(29/(I + 1))*Math.floor((21 - N)/11));
    var J = Y + Math.floor(Y/4) + I + 2 - C + Math.floor(C/4);
    J = J - 7*Math.floor(J/7);
    var L = I - J;
    var M = 3 + Math.floor((L + 40)/44);
    var D = L + 28 - 31*Math.floor(M/4);
    
    return D
}

switch (d.getMonth() + 1) {
    case 2:  // Valentine's Day
        if (day >= 7 && day <= 14) {
           newMsg = { payload: msg.payload,output:1,select:1 };
           return newMsg;
            }
        break;
    case 3:  // St. Patrick's Day
        if (day >= 15 && day <= 17) {
            newMsg = { payload: msg.payload,output:2,select:1 };
           return newMsg;
            }
        break;
    case 4: // Easter
        var E = Easter(year);
        if (day >= E - 2 && day <= E) {
           newMsg = { payload: msg.payload,output:3,select:1 };
           return newMsg;
        }
        break;
    case 5: // Memorial Day
        if (day >= 23 && day <= 25) {
           newMsg = { payload: msg.payload,output:4,select:1 };
           return newMsg;
        }
        break;
    case 7: // 4th of July
        if (day >= 1 && day <= 4) {
           newMsg = { payload: msg.payload,output:5,select:1 };
           return newMsg;
        }
        break;
    case 10: // Halloween
        if (day >= 1 && day <= 31) {
           newMsg = { payload: msg.payload,output:6,select:1 };
           return newMsg;
        }
        break;
    case 11: // Thanksgiving
        if (day >= 15 && day <= 17) {
           newMsg = { payload: msg.payload,output:7,select:1 };
           return newMsg;
        }
        break;
    case 12: // Christmas
        if (day >= 1 && day <= 31) {
            newMsg = { payload: msg.payload,output:8,select:1 };
           return newMsg;
        }
        break;
    default:
        newMsg = { payload: msg.payload,output:9,select:1 };
        return newMsg;
}

That script returns newMsg if today is one of your chosen holiday periods?
eg If it's November 15th, 16th or 17th it returns output:7 etc

Otherwise it doesn't return anything.

It seems to work for me today (November 5th, Bonfire Night! ) if define thanksgiving as day >=1 && day <=17

What problem do you see?

Thank you for the response jbudd. Yes, the script is supposed to look at today's date and then match the month. If there is a match and the date range matches, then it should send newMsg with the payload of 0 or 1 and the corresponding output and select. If there is no matches, then it should fall to the default.

It was working properly before but then I added the default and changed the return newMsg. Nothing that I would think would prevent it from working. The response I get now is nothing. I put an inject node with a payload of 0 or 1 going into this function node. Then I put a debug node on the output. I get nothing in the debug node. One time I set the month as 2 and it worked then when I made it use the default it didn't. I then changed something and now I'm back to nothing in the debug node.

try

const d = new Date();
//const d = new Date(2022,3,17); // easter 2022
var day = d.getDay(); // 0-6
var year = d.getFullYear();
var date =d.getDate(); //1-31
var month = d.getMonth() + 1;
msg.payload = 0;

function Easter(Y) {
    var C = Math.floor(Y/100);
    var N = Y - 19*Math.floor(Y/19);
    var K = Math.floor((C - 17)/25);
    var I = C - Math.floor(C/4) - Math.floor((C - K)/3) + 19*N + 15;
    I = I - 30*Math.floor((I/30));
    I = I - Math.floor(I/28)*(1 - Math.floor(I/28)*Math.floor(29/(I + 1))*Math.floor((21 - N)/11));
    var J = Y + Math.floor(Y/4) + I + 2 - C + Math.floor(C/4);
    J = J - 7*Math.floor(J/7);
    var L = I - J;
    var M = 3 + Math.floor((L + 40)/44);
    var D = L + 28 - 31*Math.floor(M/4);
    
    return D
}

switch (month) {
    case 2:  // Valentine's Day
        if (date >= 7 && date <= 14) {
           msg = { payload: 1,output:1,select:1 };
            }
        break;
    case 3:  // St. Patrick's Day
        if (date >= 15 && date <= 17) {
           msg = { payload: 1,output:2,select:1 };
            }
        break;
    case 4: // Easter
        var E = Easter(year);
        if (date >= E - 2 && date <= E) {
           msg = { payload: 1,output:3,select:1 };
        }
        break;
    case 5: // Memorial Day
        if (date >= 23 && date <= 25) {
           msg = { payload: 1,output:4,select:1 };
        }
        break;
    case 7: // 4th of July
        if (date >= 1 && date <= 4) {
           msg = { payload: 1,output:5,select:1 };
        }
        break;
    case 10: // Halloween
        if (date >= 1 && date <= 31) {
           msg = { payload: 1,output:6,select:1 };
        }
        break;
    case 11: // Thanksgiving
        if (date >= 15 && date <= 17) {
           msg = { payload: 1,output:7,select:1 };
        }
        break;
    case 12: // Christmas
        if (date >= 1 && date <= 31) {
           msg = { payload: 1,output:8,select:1 };
        }
        break;
    default:
        msg = { payload: 0,output:9,select:1 };
}
return msg

as day is 0-6 and date is 1-31

I changed the start date for the Thankgiving section:

    case 11: // Thanksgiving
        if (day >= 1 && day <= 17) {
           newMsg = { payload: msg.payload,output:7,select:1 };
           return newMsg;
        }
        break;

And it seems to work
Untitled 9

If a switch condition is met but the if in the condition is not met, you just do a return so no message is returned.
I would move the return newMsg out of all the case code and move it to the bottom the flow outside the switch block. And I would initially have as let newMsg = {payload: "nothing matches"} (or what ever you want) as the first line of the function.

This way you set a default msg if nothing matches.

Thank you everyone for all of the feedback. I found out that the issue when nothing matches. @zenofmud You mention putting let newMsg = {payload: "nothing matches"} at the beginning. I have a "default" at the bottom of the switch. I thought the default was for when nothing matched and that it didn't matter where it was placed? Thank you for letting me know about moving the return newMsg. I didn't know that would work.

Edit:
Ok, I did what you said and placed let newMsg = { payload: msg.payload,output:9,select:1 }; at the top below the year variable. Then I removed the "default" from the switch. It works perfectly now. I still don't understand why the "default" didn't work. Thanks again.

@Amishman the switch code is doing what you told it to do. For any of the months (2,3,4,5,7,10,11,12) you have case statements for, it will run that batch of code. for the other months (1,6,8,9) it will run the code in the default code.

However, not all case code will retunn a msg. For example look at July:

    case 7: // 4th of July
        if (day >= 1 && day <= 4) {
           newMsg = { payload: msg.payload,output:5,select:1 };
           return newMsg;
        }
        break;

If the day is not 1, 2, 3, or 4 you break from the case code and drop to the botton and nothing is returned.

You should leave the default in even if you just have a break there.

In your original code you coudl test by changing the switch to look at msg.payload like this:

//switch (d.getMonth() + 1) {
switch (msg.payload) {

Then send in a 1 and it will output the error msg.
Send in a 2 and it will output a msg since you are checking if today is between 7 and 14.
Send in a 3 and you will get no output because the case 3: code has an if that tests if the day is between 15 and 17 and since today is the 7th the if condition is not met and tehn yo break out of the switch and since there is nothing else there, no messge is returned.

So you see, your code was working perfectly the way you told it to, just not how you wanted it to. (computers are noterious for this :rofl:)

I hope this helps you to understand what was happening.

Just to reiterate, day outputs 0-6 sunday to saturday.
so

 case 3:  // St. Patrick's Day
        if (day >= 15 && day <= 17) 

The if statement will always be false, as day is never above 6.
In my code above i have use date, which outputs 1 - 31.

1 Like

@zenofmud Thank you for the explanation. I thought if it did not match both the case and if statement that it would send the newMsg in the default.

@E1cid Thank you for catching that. I completely missed that in your first post. I have corrected it in my script now.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.