Datumsrechnung in Shell-Scripten

Wer häufiger Shellscripte für Linux erstellt, hatte bestimmt schon häufiger das Problem, dass er das Datum des nächsten Ersten oder die Uhrzeit minus eine Stunde ermitteln musste. In vielen Scripten wird dann wild mit Shellvariablen und Shell-Funktionen herumoperiert. Dabei gibt es doch unter Linux einen viel einfacheren - und besseren - Weg mit dem Datum zu jonglieren:

Das date-Kommando, welches die meisten Linux-Distributionen standardmäßig mitliefern, wird meist nur zur formatierten Datumsausgabe verwendet. Das Kommando date +"%d.%m.%Y" gibt das aktuelle Datum in deutscher Schreibweise [Tag].[Monat].[Jahr] aus. Doch date kann noch viel mehr:

Datum mit Format

Das date-Kommando kann das Datum in unterschiedlichen Formaten ausgeben. Hierbei wird das gewünschten Format nach einem +-Zeichen übergeben. Bestimmte Zeichenkombinationen werden hierbei durch Werte aus dem aktuellen Datum ersetzt. Einen Überblick gibt die folgende Tabelle:

ZeichenBedeutung
%%Ein %-Zeichen.
%aAbgekürzter Name des Wochentages (z.B. Son, Mon). Abhängig von der aktuell eingestellten Locale.
%ADer vollständige Name des Wochentages (z.B. Sonntag). Abhängig von der aktuell eingestellten Locale.
%bAbgekürzter Name des Monats (z.B. Jan, Feb). Abhängig von der aktuell eingestellten Locale.
%BDer vollständige Name des Monats (z.B. Januar). Abhängig von der aktuell eingestellten Locale.
%cDatum und Uhrzeit in der Formatierung der aktuellen Locale.
%CDas Jahrhunder. Im Prinzip die ersten beiden Stellen der Jahreszahl.
%dTag im Monat inkl. führender Null. (z.B. 01, 11, etc.).
%DDas aktuelle Datum. Entsprich date +"%m/%d/%y".
%eTag im Monat. Bei den Tagen 1-9 mit vorangestelltem Leerzeichen. Entsprich %_d.
%FVollständiges Datum. Entsprich date +"%Y-%m-%d".
%gDie letzten beiden Stellen des Jahres der aktuellen ISO-Woche. D.h. zum Jahreswechsel zählt das Jahr, zu welchem die aktuelle Kalenderwoche (nach ISO) gehört.
%GDas Jahr der aktuellen ISO-Woche (vierstellig). D.h. zum Jahreswechsel zählt das Jahr, zu welchem die aktuelle Kalenderwoche (nach ISO) gehört. Wird normalerweise in Kombination mit %V verwendet.
%hEntspricht %b.
%HStunde im 24-Stunden-Format (00-23).
%IStunde im 12-Stunden-Format (01-12).
%jTag des Jahres (001-366).
%kStunde ohne führende 0 im 24-Stunden-Format (00-23).
%lStunde ohne führende 0 im 12-Stunden-Format (0-12).
%mMonat mit führender 0 (01-12).
%MMinute mit führender 0 (00-59).
%nEin Newline-Zeichen (\n).
%NNanosekunden (000000000..999999999)
%pDarstellung von AM und PM in der lokalen Schreibweise.
%PWie %p nur in Kleinbuchstaben (nicht ganz logisch - ich weiß)
%rUhrzeit im 12-Stunden-Format in der lokalen Schreibweise.
%RUhrzeit im 24-Stunden-Format in der lokalen Schreibweise.
%sSekunden seit 01.01.1970 00:00:00 Uhr UTC.
%SSekunden
%tEin Tab.
%TUhrzeit im Format %H:%M:%S.
%uWochentag (1..7). 1 entspricht dem Montag.
%UWochennummer im Jahr. Dabei wird der Sonntag als erster Tag der Woche angenommen.
%VISO-konforme Wochennummer (01..53).
%wWochentag (0..6). 0 entspricht dem Sonntag.
%WWochennummer im Jahr. Dabei wird der Montag als erster Tag der Woche angenommen.
%xDatumsangabe in der aktuellen, lokalen Schreibweise.
%XZeitangabe in der aktuellen, lokalen Schreibweise.
%yDie letzten zwei Stellen der Jahreszahl.
%YVierstellige Jahreszahl.
%zZeitzone als nummerische Repräsentation (z.B. +0100 für MEZ).
%:zZeitzone in der Darstellung Shh:mm (z.B. +01:00 für MEZ).
%::zZeitzone in der Darstellung Shh:mm:ss (z.B. +01:00:00 für MEZ).
%ZDarstellung der Zeitzone als Abkürzung (z.B. MEZ).

Wird nach dem Prozentzeichen eine Längenangabe eingefügt, füllt date die fehlenden Stellen standardmäßig mit Nullen auf. Die folgenden zusätzlichen Flags können dem %-Zeichen folgen um dies zu ändern:

ZeichenBedeutung
-Das Feld nicht auffüllen.
_Das Feld mit Leerzeichen auffüllen.
0Das Feld mit Nullen auffüllen.
^Wenn möglich Großbuchstaben verwenden.
#Wenn möglich Kleinbuchstaben verwenden.

Nach diesen Flags wird dann noch eine Zahl für die Feldlänge eingefügt. So gibt beispielsweise date +"%09Y" das Jahr mit 9 Stellen (z.B. 000002012) aus.

Gestern, heute, morgen

Der häufig nicht beachtete, dafür aber um so nützlichere, Parameter heißt -d. Er erlaubt es, das Datum, welches Date ausgeben soll, zu spezifizieren. Das alleine ist noch nicht sehr spektakulär, jedoch kann -d auch ungewöhnliche Datumsangaben wie “gestern” (yesterday) oder “morgen” (tomorrow) verarbeiten. Die folgenden Beispiele zeigen, was mit Datumsberechung alles möglich ist:

# Gibt das Datum des gestrigen Tages aus:
date -d "yesterday" +"%d.%m.%Y"

# Gibt das morgige Datum aus:
date -d "tomorrow" +"%d.%m.%Y"

# Gibt das Datum von heute in einer Woche aus:
date -d "+1 week" +"%d.%m.%Y"

# Gibt das Datum des gestrigen Tages vor 2 Jahren aus:
date -d "yesterday 2 years ago" +"%d.%m.%Y"

Zeit und… äh, Zeit

Natürlich funktionieren diese Angaben auch mit Zeitwerten. Dass heißt, auch die folgenden Angaben sind möglich und liefern das gewünschte Ergebnis:

# Datum und Uhrzeit vor 2 Stunden
date -d "2 hours ago"

# Datum und Uhrzeit in einer Woche und zwei Stunden
date -d "+1 week +2 hours"

Nicht jetzt, später

Ich hoffe das Prinzip ist inzwischen klar geworden. Nun stellt sich nur noch die Frage: “Was tun, wenn ich nicht mit dem aktuellen Datum rechnen will?” Auch daran haben die Macher von date gedacht. Man kann die Datums-Offsets auch mit einer Datumsangabe kombinieren: date -d "2011-01-01 +1 month" gibt wie gewünscht Tue Feb 1 00:00:00 CET 2011 aus. Man stellt also ein, von date akzeptiertes Datum, vor den Zeitoffset und schon verwendet date dieses Datum als Basis für die Offset-Berechnung.

Wer mehr über das date Kommando erfahren möchte, der sollte sich die meist installierte Info-Seite über den Befehl info date ansehen.