SAS如何自动化实现多日期工作日计算 适配月份首日星期偏移规则
修正实现
你原有代码存在几处硬伤,修正后可完全实现仅修改初始first_dt就自动同步所有关联日期的需求。
原代码错误说明
- 第一步生成月份宏变量时,
intnx里给first_dt加了引号,把宏变量当成了固定字符串,根本不会读取你定义的初始值;且拼接宏变量名用到的&monstrt、&monend未提前定义,运行会报宏解析警告 - 后续写的星期偏移宏参数定义和调用不匹配、循环变量
i从未赋值、SAS日期字面量拼接格式错误、星期值映射逻辑混乱:SAS的weekday()函数返回值1对应周日、2对应周一,你原本写的判断逻辑根本覆盖不了所有场景 - 逐星期传参判断的逻辑完全没必要,偏移规则可以用统一公式实现,代码更简洁也不容易出错
偏移规则匹配
你提到的「周一偏移5天、周二偏移6天,以此类推」的规则,和SAS星期返回值的对应关系如下,用一个取模公式就可以全覆盖,不需要写7个分支判断:
| 首日星期 | SAS weekday()返回值 | 偏移天数 |
|---|---|---|
| 周日 | 1 | 4 |
| 周一 | 2 | 5 |
| 周二 | 3 | 6 |
| 周三 | 4 | 0 |
| 周四 | 5 | 1 |
| 周五 | 6 | 2 |
| 周六 | 7 | 3 |
完整代码
/* 唯一需要手动修改的参数,改这里所有日期自动更新 */ %let first_dt = '01Jun2020'd; %let calc_range = 12; /* 计算范围:正数向后推N个月,负数向前推N个月,比如填-3就是从first_dt前3个月开始算 */ data _null_; /* 支持向前/向后连续推算,要向前算就把j的起始值改成负数,比如j=-3 to &calc_range. */ do j = 0 to &calc_range.; /* 计算当月原始起止日期 */ mon_start = intnx('month', &first_dt., j, 'b'); mon_end = intnx('month', &first_dt., j, 'e'); /* 按星期规则计算偏移天数,公式完全匹配上述偏移规则 */ offset = mod(weekday(mon_start) + 3, 7); new_mon_start = intnx('day', mon_start, offset); /* 生成全局宏变量,后续业务代码可直接调用 */ call symputx(cats("monstrt",j), put(mon_start, date9.), 'g'); call symputx(cats("monend",j), put(mon_end, date9.), 'g'); call symputx(cats("new_monstrt",j), put(new_mon_start, date9.), 'g'); end; run; /* 可选:验证生成结果 */ data check_result; do j = 0 to &calc_range.; origin_start = input(symget(cats("monstrt",j)), date9.); offset_start = input(symget(cats("new_monstrt",j)), date9.); format origin_start offset_start weekdate20.; output; end; run;
使用说明
- 日常维护只需要修改
first_dt的日期值即可,不需要动其他逻辑,所有关联日期会自动重算 - 需要向前推算连续月份时,直接修改循环的j起始值即可,比如要算first_dt之前6个月到之后12个月的所有日期,就把do语句改成
do j = -6 to 12; - 生成的宏变量按序号对应月份:
monstrt0是first_dt所在月的原始首日,monstrt1是下一月首日,monstrt-1是上一月首日,偏移后的首日存在new_monstrt+序号的宏变量里,调用时直接写&monstrt0.、&new_monstrt2.即可。
内容的提问来源于stack exchange,提问作者Soduko_junior
相关产品推荐
相关产品推荐

