AI聊天機器人的創作
這一篇所有程式均透過Gemini或ChatGPT完成,包含連文章主要說明內容,當然有做過適當的人工潤飾。
用AI寫SAS程式,自己經驗不是很好,相對Python或R來說,SAS程式很容易有錯,這一次算是難得成功,而且有很多方法確實也是超過我的能力了,把這樣的經驗和程式分享給大家
如何用SAS 精準計算工作日
手邊有兩個日期,想計算中間到底有多少個「工作天」?這不僅要扣除週末,還得考慮國定假日,甚至麻煩的補班日。如果只靠簡單的日期相減,結果一定不對。
這篇文章將用AI聊天機器人所產生的程式來解決這個問題,將程式可拆解成 5 個步驟,並讓你輕鬆套用。
0.事先說明
關於程式與程式的解釋,均由AI產生,沒有做太多的更動,某些語法我也沒有徹底瞭解,或許這就是AI時代,確認程式可以在最短時間內完成,並達成目的即可。
1. 範例資料準備
在開始之前,先建立一個包含不同情境的範例資料集 Service_Date。
/* 建立一個包含不同情境的範例資料集 */
data Service_Date;
format SERV_DT_day CREATED_DAY yymmdd10.;
input caseno $ SERV_DT_day : yymmdd10. CREATED_DAY : yymmdd10.;
datalines;
Case01 2025-01-20 2025-01-24 /* 跨一般週末 */
Case02 2025-01-27 2025-02-03 /* 跨春節連假 */
Case03 2025-02-07 2025-02-10 /* 跨補班日 2025-02-08 */
Case04 2025-04-01 2025-04-07 /* 跨兒童節/清明節連假 */
Case05 2025-05-29 2025-06-02 /* 跨端午節 */
Case06 2025-10-09 2025-10-13 /* 跨國慶日 */
Case07 2025-09-26 2025-10-02 /* 跨中秋節 */
Case08 2025-02-10 2025-02-07 /* 開始日期晚於結束日期 */
;
run;
2. 建立假日與補班日清單
先告訴 SAS 哪些日子是假日或補班日。這兩組資料將獨立儲存,以方便日後維護,如果是不同年度,可以請AI幫你產生喔,不過還是建議要檢查一下。
/* 步驟 1: 建立一個包含國定假日的資料集 */
data holidays;
input holiday : yymmdd10.;
format holiday yymmdd10.;
datalines;
2025-01-01 /* 新年 */
2025-01-27 /* 小年夜(彈性放假) */
2025-01-28 /* 除夕 */
2025-01-29 /* 春節 */
2025-01-30 /* 春節 */
2025-01-31 /* 春節 */
2025-02-01 /* 春節 */
2025-02-02 /* 春節 */
2025-02-28 /* 和平紀念日 */
2025-04-03 /* 兒童節 */
2025-04-04 /* 清明節 */
2025-05-01 /* 勞動節 */
2025-05-30 /* 端午節 */
2025-10-06 /* 中秋節 */
2025-10-10 /* 國慶日 */
;
run;
/* 步驟 4: 建立一個包含補班日的資料集 */
data makeup_workdays;
input workday : yymmdd10.;
format workday yymmdd10.;
datalines;
2025-02-08 /* 春節補班日 */
;
run;
3. 將假日清單格式化
這是整個邏輯最聰明的地方。把所有國定假日做成一個特殊的「格式」,之後只要用這個格式去檢查日期,就能快速判斷是否為假日。
/* 步驟 2 & 3: 動態產生假日格式 */
proc format;
value HOLIDAY
low-high = 1
;
run;
data holiday_fmt_ctrl;
set holidays;
fmtname = 'HOLIDAY';
type = 'N';
start = holiday;
end = holiday;
label = '0';
run;
proc format cntlin=holiday_fmt_ctrl;
run;
- proc format: 這是 SAS 專門用來建立格式的程式。
- data holiday_fmt_ctrl: 我們建立一個「控制資料集」,它的功能就是告訴 proc format 怎麼建立格式。
- label = '0': 這行是關鍵!我們將每個國定假日的標籤都設定為 0,方便之後判斷。
- proc format cntlin=...: 讀取控制資料集,將「格式」正式建立起來。
4. 核心邏輯:計算工作日
現在,將假日與補班日的資訊整合起來,並對每一筆資料進行計算。
/* 步驟 5: 計算每個個案的工作日並輸出到新資料集 */
data Service_Date_out;
/* 讀取補班日清單到記憶體中 */
array makeup_days[100] _temporary_;
retain n_makeup_days 0;
if _n_ = 1 then do;
do until(eof);
set makeup_workdays end=eof;
n_makeup_days + 1;
makeup_days[n_makeup_days] = workday;
end;
end;
set Service_Date;
if SERV_DT_day > CREATED_DAY then do;
work_days = -1;
output;
end;
else do;
work_days = 0;
do current_date = SERV_DT_day to CREATED_DAY;
/* 1. 檢查是否為補班日 */
is_makeup_workday = 0;
do i = 1 to n_makeup_days;
if current_date = makeup_days[i] then do;
is_makeup_workday = 1;
leave;
end;
end;
/* 2. 判斷是否為平日且非假日 */
is_weekday = (weekday(current_date) not in (1, 7));
is_holiday = (put(current_date, HOLIDAY.) = '0');
/* 3. 最終判斷:是補班日,或是一般工作日 */
if is_makeup_workday or (is_weekday and not is_holiday) then do;
work_days + 1;
end;
end;
output;
end;
drop is_makeup_workday is_weekday is_holiday i current_date n_makeup_days;
run;
- array..._temporary_: 建立一個臨時陣列,將補班日存入其中,這能大幅提高程式效率。
- if _n_ = 1: 這是 SAS 的一個技巧,確保這段程式碼只在第一次讀取資料時執行,將所有補班日載入陣列。
- do...to...: 建立一個迴圈,逐一檢查開始日期到結束日期之間的每一天。
- weekday(current_date) not in (1, 7): 判斷該天是否為平日(1=星期日,7=星期六)。
- put(current_date, HOLIDAY.) = '0': 利用我們前面建立的格式,判斷是否為國定假日。
- if is_makeup_workday or...: 這就是工作日計數的最終邏輯。只要符合補班日或平日且非假日其中一個條件,就將工作天數加一。
5. 驗證結果
最後,我們使用 proc print 來檢視計算結果,確認程式是否正確。
/* 輸出最終結果 */
proc print data=Service_Date_out;
run;