Jahr und Monat in ein anderes Format konvertieren

Jahr und Monat in ein anderes Format konvertieren

Ich habe Jahr und Monat im Format YYMMund möchte sie in YYYY Monthdas Format konvertieren. Das Jahr ist immer 2000 und später. Also zum Beispiel:

  • 1908wird2019 Aug
  • 1904wird2019 Apr
  • 2012wird2020 Dec
  • 2111wird2021 Nov

Ich habe das unten gezeigte Skript geschrieben:

rand=(1908 1904 2012 2001 2111)
months=(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
for i in $rand
do
    echo ${i:2:2}
    if [ ${i:2:2} -lt 1 ] || [ ${i:2:2} -gt 12 ]
        then echo "Month: ${i:2:2}. Last 2 values must be a month between 01 and 12."
    fi

    printf "20${i:0:2} ${months[${i:2:2}]}"
done

Aber ich bekomme einige Fehler.

line 13: 08: value too great for base (error token is "08")

Ich denke, dass die einstelligen Monate mit aufgefüllten Nullen an manchen Stellen ein Problem darstellen, an anderen aber funktionieren.

Ich weiß nicht genau, wie ich Bash klarmachen soll, dass es 08sich nur um handelt. Ich habe versucht, es in 8zu ändern . Aber das funktioniert nicht.${i:2:2}$((i:2:2))

line 7: i:2:2: syntax error in expression (error token is ":2:2")

Antwort1

08wird als ungültige Oktalzahl interpretiert. Es ist oktal, da es mit Null beginnt, und ungültig, da es enthält 8. Dies liegt daran, dass Sie diese Teilzeichenfolge als Zahl in einem arithmetischen Kontext verwenden (ein Ganzzahlvergleich). Sie hätten dasselbe Problem mit oder niedrigeren Zahlen, 09aber nicht .07

Das folgende Skript führt die Berechnung mit dem Datum 2000-01-01 plus dem YYBit der Zahl als Jahr durch. Anschließend fügt es den Rest der Zeichenfolge als Anzahl von Monaten hinzu und subtrahiert einen Tag. Diese Berechnung landet am letzten Tag des Monats, auf den sich der YYMMCode bezieht. Mit %Y %bwerden Jahr und Monat im YYYY MonFormat ausgegeben.

#!/bin/bash

datecodes=(1908 1904 2012 2001 2111)

for datecode in "${datecodes[@]}"; do
        printf -v thedate '2000-01-01 +%s years +%s months -1 day' "${datecode:0:2}" "${datecode:2}"
        LC_ALL=C date -d "$thedate" +'%Y %b'
done

Ausgabe:

2019 Aug
2019 Apr
2020 Dec
2020 Jan
2021 Nov

Etwas effizienterer Code, der GNU nur dateeinmal aufruft:

#!/bin/bash

datecodes=(1908 1904 2012 2001 2111)

for datecode in "${datecodes[@]}"; do
        printf '2000-01-01 +%s years +%s months -1 day\n' "${datecode:0:2}" "${datecode:2}"
done | LC_ALL=C date -f - +'%Y %b'

2013 AprBeachten Sie, dass Sie mit diesem Code beispielsweise den Code schreiben können 1040.

Um die Namen der abgekürzten Monate entsprechend dem aktuellen Gebietsschema und nicht entsprechend dem POSIX-Gebietsschema zu formatieren, entfernen Sie LC_ALL=Cvor den Aufrufen von date.


Arbeiten ohne GNU date, mit demselben Ansatz wie Sie, mit Validierung des Monatsteils des Datumscodes:

#!/bin/bash

datecodes=(1908 1904 2012 2001 2111 1040)

declare -A months
months=(
        [01]=Jan [02]=Feb [03]=Mar
        [04]=Apr [05]=May [06]=Jun
        [07]=Jul [08]=Aug [09]=Sep
        [10]=Oct [11]=Nov [12]=Dec
)

for datecode in "${datecodes[@]}"; do
        YY=${datecode:0:2}
        MM=${datecode:2}

        if [ -z "${months[$MM:-empty]}" ]; then
                printf '"%s" is an invalid month\n' "$MM" >&2
                continue
        fi

        printf '20%s %s\n' "$YY" "${months[$MM]}"
done

Dies verwendet es monthsals assoziatives Array.

Antwort2

Mit der folgenden Methode erledigt: Datum in der genannten Eingabe hinzufügen, um die gewünschte Ausgabe zu erhalten

hier habe ich das Datum "01" zur Eingabe hinzugefügt, um es in eine gültige Eingabe zu strukturieren

for i in 1908 1904 2012 2111; do date +%Y" "%b -d $i"01"; done

Ausgabe

2019 Aug
2019 Apr
2020 Dec
2021 Nov

verwandte Informationen