如何计算Korn Shell的当月最后一个工作日?

时间:2009-10-01 00:26:07

标签: date ksh

我已经看到这个问题用其他语言解答,但不是Korn Shell。我需要阻止脚本在该月的最后一个工作日运行(我们可以假设M-F是工作日,忽略假期)。

1 个答案:

答案 0 :(得分:2)

此函数适用于Bash,Korn shell和zsh,但它需要date命令(例如GNU date),它具有-d选项:

function lbdm { typeset lbdm ldm dwn m y; (( m = $1 + 1 )); if [[ $m = 13 ]]; then  m=1; (( y = $2 + 1 )); else y=$2; fi; ldm=$(date -d "$m/1/$y -1 day"); dwn=$(date -d "$ldm" +%u);if [[ $dwn = 6 || $dwn = 7 ]]; then ((offset = 5 - $dwn)); lbdm=$(date -d "$ldm $offset day"); else lbdm=$ldm; fi; echo $lbdm; }

像这样运行:

$ lbdm 10 2009
Fri Oct 30 00:00:00 CDT 2009

这是一个演示脚本,分为不同的行和更好的变量名称和一些注释:

for Month in {1..12}   # demo a whole year 
do 
    Year=2009
    LastBusinessDay=""
    (( Month = $Month + 1 ))    # use the beginning of the next month to find the end of the one we're interested in
    if [[ $Month = 13 ]]
    then
        Month=1
        (( Year++ ))
    fi;
    # these two calls to date could be combined and then parsed out
    # this first call is in "American" order, but could be changed - everything else is localized - I think
    LastDayofMonth=$(date -d "$Month/1/$Year -1 day")    # get the day before the first of the month
    DayofWeek=$(date -d "$LastDayofMonth" +%u)    # the math is easier than Sun=0 (%w)
    if [[ $DayofWeek = 6 || $DayofWeek = 7 ]]    # if it's Sat or Sun
    then
        (( Offset = 5 - $DayofWeek ))    # then make it Fri
        LastBusinessDay=$(date -d "$LastDayofMonth $Offset day")
    else
        LastBusinessDay=$LastDayofMonth
    fi
    echo "$LastDayofMonth - $DayofWeek - $LastBusinessDay"
done

输出:

Sat Jan 31 00:00:00 CST 2009 - 6 - Fri Jan 30 00:00:00 CST 2009
Sat Feb 28 00:00:00 CST 2009 - 6 - Fri Feb 27 00:00:00 CST 2009
Tue Mar 31 00:00:00 CDT 2009 - 2 - Tue Mar 31 00:00:00 CDT 2009
Thu Apr 30 00:00:00 CDT 2009 - 4 - Thu Apr 30 00:00:00 CDT 2009
Sun May 31 00:00:00 CDT 2009 - 7 - Fri May 29 00:00:00 CDT 2009
Tue Jun 30 00:00:00 CDT 2009 - 2 - Tue Jun 30 00:00:00 CDT 2009
Fri Jul 31 00:00:00 CDT 2009 - 5 - Fri Jul 31 00:00:00 CDT 2009
Mon Aug 31 00:00:00 CDT 2009 - 1 - Mon Aug 31 00:00:00 CDT 2009
Wed Sep 30 00:00:00 CDT 2009 - 3 - Wed Sep 30 00:00:00 CDT 2009
Sat Oct 31 00:00:00 CDT 2009 - 6 - Fri Oct 30 00:00:00 CDT 2009
Mon Nov 30 00:00:00 CST 2009 - 1 - Mon Nov 30 00:00:00 CST 2009
Thu Dec 31 00:00:00 CST 2009 - 4 - Thu Dec 31 00:00:00 CST 2009

注意:我在测试期间发现,如果你试图在第二次世界大战期间使用它,那么由于CWT和CPT这样的战时时区而失败了。

编辑:这是一个应该在AIX和其他无法使用上述功能的系统上运行的版本。它应该适用于Bourne,Bash,Korn和zsh。

function lbdN { cal $1 $2 | awk 'NF == 0 {next} FNR > 2 {week = $0} END {num = split(week, days); lbdN = days[num]; if ( num == 1 ) { lbdN -= 2 }; if ( num == 7 ) { lbdN-- }; print lbdN }'; }

如果cal周一开始几周,您可能需要进行调整。

以下是如何使用它:

month=12; year=2009    # if these are unset or null, the current month/year will be used
if [[ $(date +%d) == $(lbdN $month $year) ]]; 
then
    echo "Don't do stuff today"
else
    echo "It's not the last business day of the month"
fi

对shell的if ... then语法进行适当的调整。

修改错误修复:由于使用lbdN的方式,2月在28日星期六结束时,先前版本的tail失败了。新版本修复了这个问题。它仅使用calawk

修改:为了完整起见,我认为在本月的第一个工作日添加功能会很方便。

date需要-d

function fbdm { typeset dwn d; dwn=$(date -d "$1/1/$2" +%u); d=1; if [[ $dwn = 6 || $dwn = 7 ]]; then (( d = 9 - $dwn )); fi; echo $(date -d "$1/$d/$2"); }

2010年5月:

Mon May 3 00:00:00 CDT 2010

仅需要calawk

function fbdN { cal $1 $2 | awk 'FNR == 3 { week = $0 } END { num = split(week, days); fbdN = days[1]; if ( num == 1 ) { fbdN += 2 }; if ( num == 7 ) { fbdN++ }; print fbdN }'; }

2010年8月:

2