Come calcolare l'ultimo giorno lavorativo del mese in Korn Shell?
Domanda
Ho visto questa domanda ha risposto in altre lingue, ma non la Korn Shell. Ho bisogno di evitare che uno script viene eseguito l'ultimo giorno lavorativo del mese (possiamo supporre M-F sono giorni lavorativi, ignorare i giorni festivi).
Soluzione
Questa funzione lavora a Bash, Korn shell e zsh, ma richiede un comando date
(come GNU date
) che ha l'opzione -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; }
Esegui in questo modo:
$ lbdm 10 2009
Fri Oct 30 00:00:00 CDT 2009
Ecco uno script demo suddiviso in linee separate e con migliori nomi delle variabili e alcuni commenti:
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
Output:
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
. Nota: ho scoperto durante la prova che se si tenta di utilizzare questo per date in giro per la seconda guerra mondiale che non riesce a causa di fusi orari in tempo di guerra come CWT e CPT
Modifica : Ecco una versione che dovrebbe funzionare su AIX e altri sistemi che non possono utilizzare quanto sopra. Dovrebbe funzionare su Bourne, Bash, Korn e 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 }'; }
Potrebbe essere necessario apportare modifiche se il vostro cal
inizia settimane il Lunedi.
Ecco come si può utilizzare:
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
fare aggiustamenti appropriati per la sintassi if
... then
della shell, naturalmente.
Modifica : Bug Fix : La versione precedente di lbdN
fallì quando febbraio termina il Sabato 28 a causa del modo in passato tail
. La nuova versione corregge questo. Si utilizza solo cal
e awk
.
Modifica :. Per completezza, ho pensato che sarebbe stato utile per comprendere le funzioni per il primo giorno lavorativo del mese
Richiede date
con -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"); }
Per maggio 2010:
Mon May 3 00:00:00 CDT 2010
Richiede cal
e awk
solo:
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 }'; }
Per agosto 2010:
2