分享 在NodeRed中使用function 來判斷當天是否為假日的2種方式

公司的梯廳燈一直是用手動的方式在做自動化
遇到連假或者補班都需要手動去更改
原本的方式如下

但是有時在忙就會忘了去改,變成還是照既定的設定在跑
而且最近一直都在玩ChatGPT所以就透過ChatGPT做出了判斷假日的方式

第一種比較簡單只要每年元旦去修改

var holidays = [
    "0403",
    "0404",
    "0405",
    "0622",
    "0623",
    "0929",
    "1009",
    "1010"
];

var offdays = [
    "0325",
    "0617",
    "0921"
];

// 將特定的節日日期轉換為 JavaScript 的 Date 物件
function getHolidayDate(dateString) {
    var today = new Date();
    var year = today.getFullYear();
    var month = dateString.substr(0, 2) - 1; // JavaScript 的月份是從 0 開始算起,因此要減 1
    var day = dateString.substr(2, 2);
    return new Date(year, month, day);
}

// 判斷特定日期是否為節假日
function isHoliday(date) {
    var dateString = ("0" + (date.getMonth() + 1)).slice(-2) + ("0" + date.getDate()).slice(-2);
    return holidays.indexOf(dateString) > -1;
}

// 判斷特定日期是否為補班日
function isOffday(date) {
    var dateString = ("0" + (date.getMonth() + 1)).slice(-2) + ("0" + date.getDate()).slice(-2);
    return offdays.indexOf(dateString) > -1;
}

// 判斷特定日期是否為週末
function isWeekend(date) {
    return date.getDay() === 0 || date.getDay() === 6;
}

var today = new Date();

// 如果今天是補班日,優先顯示為上班
if (isOffday(today)) {
    msg.payload = "上班";
// 如果是節假日,顯示為放假
} else if (isHoliday(today)) {
    msg.payload = "放假";
// 如果是週末,但不是補班日,顯示為週末
} else if (isWeekend(today)) {
    msg.payload = "週末";
// 其他情況顯示為上班
} else {
    msg.payload = "上班";
}

return msg;

holidays 為禮拜一到禮拜五放假的日期
offdays 為補班的日期
將上面的部分直接複製貼上NR的function就可以套用今年2023年行政院人事行政局公告的行事曆

這樣就能在元旦設定完以後就不用再去管當年的休假補班日了

上圖為修改完後的flow

當然我們玩HA都是希望能完全的自動化連改都不想去改
直接套用當年的行事曆這樣才能達成懶的境界
因此有了第二種方式的出現

第二種使用了Google Calendar 的台灣節假日來當判斷條件
前置作業

  1. HA安裝Google Calendar
    依照下方連結安裝及取得授權
    Google Calendar官方安裝說明文件
    Google Calendar授權取得說明影片

image

以下為 function 內容

var today = new Date();
var options = { year: 'numeric', month: '2-digit', day: '2-digit', timeZone: "Asia/Taipei" };
var formatter = new Intl.DateTimeFormat('zh-TW', options);
var today_date = formatter.format(today).replace(/\//g, '-');
var today_weekday = today.getDay();
var taiwan_holiday = global.get('homeassistant').homeAssistant.states['calendar.tai_wan_jie_jia_ri'];
var holidays_start = taiwan_holiday.attributes.start_time.slice(0, 10);
var holidays_end = taiwan_holiday.attributes.end_time.slice(0, 10);
var holidays_message = taiwan_holiday.attributes.message;
var not_holidays = [
    "農民節",
    "元宵節",
    "婦女節",
    "中元節",
    "軍人節",
    "教師節",
    "重陽節",
    "台灣光復節",
    "青年節",
    "行憲紀念日"
];

if (today_weekday === 0) {
    msg.payload = "今天休假日";
} else if (today_weekday === 6) {
    if (today_date === holidays_start && holidays_message.includes('補班')) {
        msg.payload = "今天為上班日:" + holidays_message;
    } else {
        msg.payload = "今天為休假日";
    }
} else {
    if (today_date >= holidays_start && today_date <= holidays_end) {
        if (holidays_message.includes('補假') || holidays_message.includes('中華民國')) {
            msg.payload = "今天為休假日:" + holidays_message;
        } else if (not_holidays.some(substring => holidays_message.includes(substring))) {
            msg.payload = "今天為上班日";
        } else {
            msg.payload = "今天為休假日:" + holidays_message;
        }
    } else {
        msg.payload = "今天為上班日";
    }
}
msg.payload_all = "日期:" + today_date + "星期" + today_weekday + ",台灣假日日期為:" + holidays_start + "-" + holidays_end + "節日為:" + holidays_message;

return msg;

not_holidays 為Google Calendar裡面列為假日但實際沒有放假的節日
可以依照個人需求去添加修改
整個function流程
如果當天為
週日直接列為休假日
週六則比對台灣節假日的message裡面是否含有補班有則列為上班日沒有則為休假日
週一到五則比對message not_holidays 以及是否含有補假來判斷為上班日還是休假日

第一種方式簡單就是每年要改一次
第二種方式只有取得授權比較麻煩但是弄好以後再來就都不用管他
各有利弊
而第二種方式也可以更改成個人在Google Calendar裡面的行事曆
去做其他的變化
不過這不在本次分享的範圍
希望能幫助到有需求的朋友
以上為這次分享

感謝紅軍大的分享,這邊提供優化後的function node版本,分兩路輸出,上路為workday的on/ off,下路為holiday的on/ off:

[{"id":"2b3e9447d7dc2799","type":"function","z":"87b599f5.059ae8","name":"Workday?","func":"//Definition  of output Object\nvar Day_Holiday = {};\nvar Day_Workday = {};\n\nvar today = new Date();\nvar options = { year: 'numeric', month: '2-digit', day: '2-digit', timeZone: \"Asia/Taipei\" };\nvar formatter = new Intl.DateTimeFormat('zh-TW', options);\nvar today_date = formatter.format(today).replace(/\\//g, '-');\nvar today_weekday = today.getDay();\nvar taiwan_holiday = global.get('homeassistant').homeAssistant.states['calendar.tai_wan_de_jie_qing_jia_ri'];\nvar holidays_start = taiwan_holiday.attributes.start_time.slice(0, 10);\nvar holidays_end = taiwan_holiday.attributes.end_time.slice(0, 10);\nvar holidays_message = taiwan_holiday.attributes.message;\nvar not_holidays = [\n    \"農民節\",\n    \"元宵節\",\n    \"婦女節\",\n    \"中元節\",\n    \"軍人節\",\n    \"教師節\",\n    \"重陽節\",\n    \"台灣光復節\",\n    \"青年節\",\n    \"行憲紀念日\"\n];\nvar day_type = {};\n\nif (today_weekday === 0) {\n    day_type = \"Holiday\";\n} else if (today_weekday === 6) {\n    if (today_date === holidays_start && holidays_message.includes('補班')) {\n        day_type = \"Workday\";\n    } else {\n        day_type = \"Holiday\";\n    }\n} else {\n    if (today_date >= holidays_start && today_date <= holidays_end) {\n        if (holidays_message.includes('補假') || holidays_message.includes('中華民國')) {\n            day_type = \"Holiday\";\n        } else if (not_holidays.some(substring => holidays_message.includes(substring))) {\n            day_type = \"Workday\";\n        } else {\n            day_type = \"Holiday\";\n        }\n    } else {\n        day_type = \"Workday\";\n    }\n}\nmsg.payload_all = \"日期:\" + today_date + \" 星期\" + today_weekday + \" ,台灣假日日期為:\" + holidays_start + \"~\" + holidays_end + \" 節日為:\" + holidays_message;\n\nif (day_type === 'Workday') {\n    Day_Workday.payload  = 'on';\n    Day_Holiday.payload = 'off';\n} else if (day_type === 'Holiday') {\n    Day_Workday.payload = 'off';\n    Day_Holiday.payload = 'on';\n} else {\n    Day_Workday.payload = 'off';\n    Day_Holiday.payload = 'off';\n}\n\nnode.send( Day_Workday ); \nnode.send([null, Day_Holiday ]);","outputs":2,"noerr":0,"initialize":"","finalize":"","libs":[],"x":200,"y":640,"wires":[["1d5691e53184e250"],["817c6f8351e65148","cefe042d.9d7208"]]}]

實際flow應用如下:
image

2個讚

謝謝分享
請問第一種方法,如果 上班時間是星期1至星期6要如何修改

將|| date.getDay() === 6 拿掉
改成

function isWeekend(date) {
    return date.getDay() === 0;
}

這樣就會變成只有禮拜天是假日

ok了 謝謝指導

請問出現"TypeError: Cannot read properties of undefined (reading ‘states’)"
的錯誤訊息是該怎麼修正函數?

抓不到資料
比對一下實體是否正確

1個讚

謝謝指導
我爬路徑,發現是實體的路徑英文大小寫不同導致報錯。