Benutzer-Werkzeuge

Webseiten-Werkzeuge


comp:ftagebash

Unterschiede

Hier werden die Unterschiede zwischen zwei Versionen gezeigt.

Link zu dieser Vergleichsansicht

comp:ftagebash [2014-08-12 1702] (aktuell)
werner angelegt
Zeile 1: Zeile 1:
 +====== Bash: Feiertage ======
 +
 +Der folgende Code ist entstanden, als es galt, eine Feiertagsprüfung in Bash (wahlweise AWK) umzusetzen. Also habe ich mal die Feiertage für Sachsen und Sachsen-Anhalt berechnen lassen... Ist nicht schnell, aber funktioniert.
 +
 +Historisch gesehen, habe ich das zum ersten Mal Ende der 80er Jahre in Pascal geschrieben,​ später in VBA für Excel 5.0 (deutsch), Excel 97 (englisch), PHP, Perl, ... und nun eben zum ersten Mal in Bash :-)
 +
 +<file bash /​usr/​local/​bin/​kalender.sh>​
 +#!/bin/bash
 +
 +# Funktionssammlung fuer Kalenderzwecke
 +# checkJahr $JAHR
 +# checkMonat $MONAT
 +# checkTag $TAG $MONAT $JAHR
 +# is_Leapyear $JAHR
 +# cal_days_in_month $MONAT $JAHR
 +# getKarfreitag $JAHR
 +# getOstersonntag $JAHR
 +# getOstermontag $JAHR
 +# getHimmelfahrt $JAHR
 +# getAdvent1 $JAHR
 +# getAdvent2 $JAHR
 +# getAdvent3 $JAHR
 +# getAdvent4 $JAHR
 +# getWochentag $TAG $MONAT $JAHR
 +# istFeiertag $TAG $MONAT $JAHR
 +
 +EWIGERKALENDER='​ewkal.sh'​
 +[ -f "​$EWIGERKALENDER"​ ] && . "​$EWIGERKALENDER"​
 +
 +# testet, ob das angegebene Jahr eine vierstellige Zahl und mindestens 1683 ist
 +# Param1: Jahreszahl
 +# Rückgabe: 1 bei Fehler, 0 wenn OK
 +#           ​außerdem wird $? gesetzt
 +checkJahr() {
 +    # integer, > 1683
 +    TESTJAHR=${1:​-0}
 +    VERSJ=$(echo "​$TESTJAHR"​ | tr -d '​[0-9]'​)
 +    [ -z "​$VERSJ"​ ] || return 1
 +    if [[ $TESTJAHR =~ ^[0-9]+$ ]] && [ $TESTJAHR -gt 1683 ]; then
 +        echo 0
 +        return 0
 +    else
 +        echo 1
 +        return 1
 +    fi
 +} # checkJahr
 +
 +# testet, ob der angegebene Jahr Monat im Bereich 1 bis 12 liegt
 +# Param1: Monatsnummer
 +# Rückgabe: 1 bei Fehler, 0 wenn OK
 +#           ​außerdem wird $? gesetzt
 +checkMonat() {
 +    # integer, Bereich 1..12
 +    TESTMONAT=${1:​-0}
 +    if [[ $TESTMONAT =~ ^[0-9]+$ ]] && [ $TESTMONAT -ge 1 -a $TESTMONAT -le 12 ]; then
 +        echo 0
 +        return 0
 +    else
 +        echo 1
 +        return 1
 +    fi
 +} # checkMonat
 +
 +# teste, ob es sich um ein Schaltjahr handelt
 +# Param1: Jahreszahl
 +# Rückgabe: Text 0 bei Fehler, Text 1 wenn OK
 +#           ​außerdem wird $? gesetzt
 +is_Leapyear() {
 +    RETVAL=9
 +    TESTJAHR=${1:​-0}
 +    JAHR_OK=$(checkJahr $TESTJAHR)
 +    if [ "​x$JAHR_OK"​ != '​x0'​ ]; then
 +        echo $RETVAL
 +        return $RETVAL
 +    fi
 +    if [ $(($TESTJAHR % 100)) -ne 0 -a  $(($TESTJAHR % 4)) -eq 0 ]; then
 +        RETVAL=1
 +    elif [ $(($TESTJAHR % 400)) == 0 ]; then
 +        RETVAL=1
 +    else
 +        RETVAL=0
 +    fi
 +    echo $RETVAL
 +    return $RETVAL
 +} # is_Leapyear
 +
 +# Anzahl Tage im Kalendermonat
 +# Param1: Monatszahl, siehe checkMonat
 +# Param2: Jahreszahl, siehe checkJahr
 +# Rückgabe: eine Zahl im Bereich 28..31, je nachdem :-)
 +#           im Fehlerfall eine 1 (Errorlevel wird gesetzt)
 +cal_days_in_month() {
 +    TESTMONAT=${1:​-0}
 +    TESTJAHR=${2:​-0}
 +    JAHR_OK=$(checkJahr $TESTJAHR)
 +    MONAT_OK=$(checkMonat $TESTMONAT)
 +    if [ "​x$JAHR_OK"​ != '​x0'​ -o "​x$MONAT_OK"​ != '​x0'​ ]; then
 +        echo 1
 +        return 1
 +    fi
 +    case $TESTMONAT in
 +        1|3|5|7|8|10|12) ​       RETVAL=31 ​      ;;
 +        4|6|9|11) ​              ​RETVAL=30 ​      ;;
 +        2)                      if [ is_Leapyear $TESTJAHR ]; then
 +                                    RETVAL=29
 +                                else
 +                                    RETVAL=28
 +                                fi
 +                                                ;;
 +    esac
 +    echo $RETVAL
 +} # cal_days_in_month
 +
 +# testet, ob ein Tag im erlaubten Bereich (Monatslänge) ist
 +# Param1: Tageszahl
 +# Param2: Monatszahl, siehe checkMonat
 +# Param3: Jahreszahl, siehe checkJahr
 +# Rückgabe: Tageszahl (Param1), wenn Tag möglich ist
 +#           sonst letzter Tag des Monats
 +#           $? = 0, wenn Tag möglich ist, 1 sonst
 +checkTag() {
 +    TESTTAG=${1:​-0}
 +    TESTMONAT=${2:​-0}
 +    TESTJAHR=${3:​-0}
 +    [ "​x${TESTTAG:​0:​1}" ​  = '​x0'​ ] && TESTTAG="​${TESTTAG:​1:​1}"​
 +    [ "​x${TESTMONAT:​0:​1}"​ = '​x0'​ ] && TESTMONAT="​${TESTMONAT:​1:​1}"​
 +#    echo "​testjahr=$TESTJAHR,​ testmonat=$TESTMONAT (x${TESTMONAT:​0:​2}),​ testtag=$TESTTAG"​ >> /tmp/jahr4
 +    TAG_OK=$(echo $TESTTAG | tr -d [0-9])
 +#    if [[ $TESTTAG =~ ^[0-9]+$ ]] && [[ $TESTTAG -lt 1 ]]; then
 +    let "​TESTTAG *= 1"
 +    if [ -z "​$TAG_OK"​ -a $TESTTAG -ge 1 ]; then
 +        :
 +    else
 +        echo 1
 +        return 1
 +    fi
 +    JAHR_OK=$(checkJahr $TESTJAHR)
 +    if [ "​x$JAHR_OK"​ != "​x0"​ ]; then
 +        echo 2
 +        return 1
 +    fi
 +    MON_OK=$(checkMonat $TESTMONAT)
 +    if [ "​x$MON_OK"​ != '​x0'​ ]; then
 +        echo 3
 +        return 1
 +    fi
 +    MAXTAGE=$(cal_days_in_month $TESTMONAT $TESTJAHR)
 +    if [ $MAXTAGE -ge $TESTTAG ]; then
 +        echo $TESTTAG
 +        return 0
 +    else
 +        echo $MAXTAGE
 +        return 1
 +    fi
 +} # checkTag
 +
 +# berechnet das Osterdatum nach Gauss
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Ostersonntag im Format YYYY-MM-DD
 +getOstersonntag() {
 +    TESTJAHR=${1:​-0}
 +    [ $TESTJAHR -eq 0 ] && TESTJAHR=$(date +%Y)
 +    G=$(expr $TESTJAHR % 19 + 1)
 +    C=$(expr $TESTJAHR / 100 + 1)
 +    X=$(expr \( $C / 4 - 4 \) \* 3)
 +    Z=$(expr \( $C \* 8 + 5 \) / 25 - 5)
 +    D=$(expr $TESTJAHR \* 5 / 4 - $X - 10)
 +    E=$(expr \( $G \* 11 + $Z - $X + 20 \) % 30)
 +    [ $E -lt 0 ] && E=$(expr $E + 30)
 +    [ $E -eq 25 -a $G -gt 11 -o $E -eq 24 ] && E=$(expr $E + 1)
 +    TAG=$(expr 44 - $E)
 +    [ $TAG -lt 21 ] && TAG=$(expr $TAG + 30)
 +    TAG=$(expr $TAG + 7 - \( $D + $TAG \) % 7)
 +    if [ $TAG -gt 31 ] ; then
 +       ​TAG=$(expr $TAG - 31)
 +       MON=4
 +    else
 +       MON=3
 +    fi
 +    echo "​$TESTJAHR-$MON-$TAG"​
 +} # getOstersonntag
 +
 +# berechnet das Datum des 1. Advent
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getAdvent1() {
 +    DJHR=$1
 +    # numerisch?
 +    TSTJHR=$(echo "​DJHR"​ | tr -d '​[0-9]'​)
 +    [ -z "​$TSTJHR"​ ] || DJHR=$(date +%Y)
 +    # lang genug?
 +    [ "​x${#​DJHR}"​ = '​x4' ​ ] || DJHR=$(date +%Y)
 +    DMON=11
 +    DTAG=27
 +    ZIELWOTAG='​So'​
 +    ISTWOTAG=$(getWochentag $DTAG $DMON $DJHR)
 +    while [ "​$ZIELWOTAG"​ != "​$ISTWOTAG"​ ]; do
 +        STICHSEK=$(date -d "​${DJHR}-${DMON}-${DTAG}"​ +%s)
 +        let "​STICHSEK += 86400"
 +        DTAG=$(date -d "​@$STICHSEK"​ +%d)
 +        DMON=$(date -d "​@$STICHSEK"​ +%m)
 +        ISTWOTAG=$(getWochentag $DTAG $DMON $DJHR)
 +    done
 +    date -d "​@$STICHSEK"​ +'​%Y-%m-%d'​
 +} # getAdvent1
 +
 +# berechnet das Datum des 2. Advent
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getAdvent2() {
 +    DJHR=$1
 +    # numerisch?
 +    TSTJHR=$(echo "​DJHR"​ | tr -d '​[0-9]'​)
 +    [ -z "​$TSTJHR"​ ] || DJHR=$(date +%Y)
 +    # lang genug?
 +    [ "​x${#​DJHR}"​ = '​x4' ​ ] || DJHR=$(date +%Y)
 +    # Basis: 1. Advent
 +    ADV1=$(getAdvent1 $DJHR)
 +    SEKDAT=$(date -d "​$ADV1"​ +%s)
 +    # plus eine Woche
 +    DIFF=$((7 * 86400))
 +    let "​SEKDAT += DIFF"
 +    date -d "​@$SEKDAT" ​ +'​%Y-%m-%d'​
 +} # getAdvent2
 +
 +# berechnet das Datum des 3. Advent
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getAdvent3() {
 +    DJHR=$1
 +    # numerisch?
 +    TSTJHR=$(echo "​DJHR"​ | tr -d '​[0-9]'​)
 +    [ -z "​$TSTJHR"​ ] || DJHR=$(date +%Y)
 +    # lang genug?
 +    [ "​x${#​DJHR}"​ = '​x4' ​ ] || DJHR=$(date +%Y)
 +    # Basis: 1. Advent
 +    ADV1=$(getAdvent1 $DJHR)
 +    SEKDAT=$(date -d "​$ADV1"​ +%s)
 +    # plus zwei Wochen
 +    DIFF=$((2 * 7 * 86400))
 +    let "​SEKDAT += DIFF"
 +    date -d "​@$SEKDAT" ​ +'​%Y-%m-%d'​
 +} # getAdvent3
 +
 +# berechnet das Datum des 4. Advent
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getAdvent4() {
 +    DJHR=$1
 +    # numerisch?
 +    TSTJHR=$(echo "​DJHR"​ | tr -d '​[0-9]'​)
 +    [ -z "​$TSTJHR"​ ] || DJHR=$(date +%Y)
 +    # lang genug?
 +    [ "​x${#​DJHR}"​ = '​x4' ​ ] || DJHR=$(date +%Y)
 +    # Basis: 1. Advent
 +    ADV1=$(getAdvent1 $DJHR)
 +    SEKDAT=$(date -d "​$ADV1"​ +%s)
 +    # plus drei Wochen
 +    DIFF=$((3 * 7 * 86400))
 +    let "​SEKDAT += DIFF"
 +    date -d "​@$SEKDAT" ​ +'​%Y-%m-%d'​
 +} # getAdvent4
 +
 +# berechnet das Datum des Buß- und Bettags
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getBusstag() {
 +    DJHR=$1
 +    # numerisch?
 +    TSTJHR=$(echo "​$DJHR"​ | tr -d '​[0-9]'​)
 +    [ -z "​$TSTJHR"​ ] || DJHR=$(date +%Y)
 +    # lang genug?
 +    [ "​x${#​DJHR}"​ = '​x4' ​ ] || DJHR=$(date +%Y)
 +    # Basis: 1. Advent
 +    ADV1=$(getAdvent1 $DJHR)
 +    SEKDAT=$(date -d "​$ADV1"​ +%s)
 +    # minus 10 tage
 +    DIFF=$((10 * 86400))
 +    let "​SEKDAT -= $DIFF"
 +    date -d "​@$SEKDAT" ​ +'​%Y-%m-%d'​
 +} # getBusstag
 +
 +# berechnet das Datum des Ostermontags
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getOstermontag() {
 +    ODAT=$1
 +    [ -z "​$ODAT"​ ] && return 1
 +    # in Sekunden umwandeln
 +    OSONN=$(date -d "​$ODAT"​ +%s)
 +    # Differenz hinzu
 +    OMONTAG=$(($OSONN + 86400))
 +    # im Format YYYY-MM-DD ausgeben
 +    date -d "​@$OMONTAG"​ +'​%Y-%m-%d'​
 +} # getOstermontag
 +
 +# berechnet das Datum des Karfreitags
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getKarfreitag() {
 +    ODAT=$1
 +    [ -z "​$ODAT"​ ] && return 1
 +    # in Sekunden umwandeln
 +    OSONN=$(date -d "​$ODAT"​ +%s)
 +    # Differenz hinzu
 +    SEKDIFF=$((2 * 86400))
 +    KARFTAG=$(($OSONN + $SEKDIFF))
 +    # im Format YYYY-MM-DD ausgeben
 +    date -d "​@$KARFTAG"​ +'​%Y-%m-%d'​
 +} # getKarfreitag
 +
 +# berechnet das Datum des Pfingstsonntags
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getPfingstsonntag() {
 +    ODAT=$1
 +    [ -z "​$ODAT"​ ] && return 1
 +    # in Sekunden umwandeln
 +    OSONN=$(date -d "​$ODAT"​ +%s)
 +    # Differenz hinzu
 +    SEKDIFF=$((49 * 86400))
 +    PFSONN=$(($OSONN + $SEKDIFF))
 +    # im Format YYYY-MM-DD ausgeben
 +    date -d "​@$PFSONN"​ +'​%Y-%m-%d'​
 +} # getPfingstsonntag
 +
 +# berechnet das Datum des Pfingstmontags
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getPfingstmontag() {
 +    ODAT=$1
 +    [ -z "​$ODAT"​ ] && return 1
 +    # in Sekunden umwandeln
 +    OSONN=$(date -d "​$ODAT"​ +%s)
 +    # Differenz hinzu
 +    SEKDIFF=$((50 * 86400))
 +    PFMON=$(($OSONN + $SEKDIFF))
 +    # im Format YYYY-MM-DD ausgeben
 +    date -d "​@$PFMON"​ +'​%Y-%m-%d'​
 +} # getPfingstmontag
 +
 +# berechnet das Datum von Christi Himmelfahrt
 +# Param1: Jahreszahl, siehe checkJahr
 +# Rückgabe: Datum im Format YYYY-MM-DD
 +getHimmelfahrt() {
 +    ODAT=$1
 +    [ -z "​$ODAT"​ ] && return 1
 +    # in Sekunden umwandeln
 +    OSONN=$(date -d "​$ODAT"​ +%s)
 +    # Differenz hinzu
 +    SEKDIFF=$((39 * 86400))
 +    HIFAH=$(($OSONN + $SEKDIFF))
 +    # im Format YYYY-MM-DD ausgeben
 +    date -d "​@$HIFAH"​ +'​%Y-%m-%d'​
 +} # getHimmelfahrt
 +
 +# prüft, ob es sich beim übergebenen Datum um einen Feiertag handelt
 +# Param1: Tageszahl, siehe checkTag
 +# Param2: Monatszahl, siehe checkMonat
 +# Param3: Jahreszahl, siehe checkJahr
 +# Param4: Region; '​SN'​ -> Sachsen, '​SA'​ -> Sachsen-Anhalt
 +# Rückgabe: 1 wenn Feiertag, 0 sonst
 +#           $? wird entsprechend gesetzt
 +istFeiertag() {
 +    TAG=${1:-0}
 +    MONAT=${2:​-0}
 +    JAHR=${3:​-0}
 +    INREGION=${4:​-'​SN'​}
 +    RETID=0
 +    [ "​x$JAHR" ​ = "​x0"​ ] && JAHR=$(date +%Y)
 +    [ "​x$MONAT"​ = "​x0"​ ] && MONAT=$(date +%m)
 +    [ "​x$TAG" ​  = "​x0"​ ] && TAG=$(date +%d)
 +    JAHR_OK=$(checkJahr $JAHR)
 +    if [ "​x$JAHR_OK"​ != '​x0' ​ ]; then
 +        echo 0
 +        return 1
 +    fi
 +    [ "​x${TAG:​0:​1}"​ = '​x0'​ ] && TAG=${TAG:​1:​1}
 +    [ "​x${MON:​0:​1}"​ = '​x0'​ ] && MON=${MON:​1:​1}
 +    VGLTAG=$(checkTag $TAG $MONAT $JAHR)
 +    [ $VGLTAG -ne $TAG ] && return 1
 +    FEIER=0
 +    if [ $MONAT -eq 12 ]; then
 +        case "​$TAG"​ in
 +            24|25|26|31)
 +                FEIER=1
 +                ;;
 +        esac
 +    elif [ $MONAT -eq 10 ]; then
 +        case $TAG in
 +            3|31)
 +                FEIER=1
 +                ;;
 +        esac
 +    elif [ $MONAT -eq 5 -a $TAG -eq 1 ]; then
 +        FEIER=1
 +    elif [ $MONAT -eq 1 -a $TAG -eq 1 ]; then
 +        FEIER=1
 +    fi
 +    if [ $FEIER -eq 0 ]; then
 +        VGLDAT="​${JAHR}-${MONAT}-${TAG}"​
 +        # jetzt die beweglichen Feiertage
 +        # Lassen wir die Sonntage mal raus ;-)
 +        KFDAT=$(getKarfreitag $JAHR)
 +#        OSDAT=$(getOstersonntag $JAHR)
 +        OMDAT=$(getOstermontag $JAHR)
 +        HFDAT=$(getHimmelfahrt $JAHR)
 +#        PSDAT=$(getPfingstsonntag $JAHR)
 +        PMDAT=$(getPfingstmontag $JAHR)
 +#        A1DAT=$(getAdvent1 $JAHR)
 +#        A2DAT=$(getAdvent2 $JAHR)
 +#        A3DAT=$(getAdvent3 $JAHR)
 +#        A4DAT=$(getAdvent4 $JAHR)
 +        if [ "​$VGLDAT"​ = "​$KFDAT"​ ]; then
 +            FEIER=1
 +#               elif [ "​$VGLDAT"​ = "​$OSDAT"​ ]; then
 +#                       ​FEIER=1
 +        elif [ "​$VGLDAT"​ = "​$OMDAT"​ ]; then
 +            FEIER=1
 +        elif [ "​$VGLDAT"​ = "​$HFDAT"​ ]; then
 +            FEIER=1
 +#               elif [ "​$VGLDAT"​ = "​$PSDAT"​ ]; then
 +#                       ​FEIER=1
 +        elif [ "​$VGLDAT"​ = "​$PMDAT"​ ]; then
 +            FEIER=1
 +#               elif [ "​$VGLDAT"​ = "​$A1DAT"​ ]; then
 +#                       ​FEIER=1
 +#               elif [ "​$VGLDAT"​ = "​$A2DAT"​ ]; then
 +#                       ​FEIER=1
 +#               elif [ "​$VGLDAT"​ = "​$A3DAT"​ ]; then
 +#                       ​FEIER=1
 +#               elif [ "​$VGLDAT"​ = "​$A4DAT"​ ]; then
 +#                       ​FEIER=1
 +        fi
 +    fi
 +    if [ $FEIER -eq 0 ]; then
 +        # jetzt die bundeslandabhängigen Feiertage
 +        if [ "​$INREGION"​ = '​SN'​ ]; then
 +            BBDAT=$(getBusstag $JAHR)
 +            if [ "​x$VGLDAT"​ = "​x$BBDAT"​ ]; then
 +                FEIER=1
 +            fi
 +        else
 +            if [ "​$VGLDAT"​ = "​${JAHR}-01-06"​ ]; then
 +                FEIER=1
 +            fi
 +        fi
 +    fi
 +    echo "​$FEIER"​
 +    return $FEIER
 +} # istFeiertag
 +</​file>​
  
comp/ftagebash.txt · Zuletzt geändert: 2014-08-12 1702 von werner