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:

Zeichen Bedeutung
%% Ein %-Zeichen.
%a Abgekürzter Name des Wochentages (z.B. Son, Mon). Abhängig von der aktuell eingestellten Locale.
%A Der vollständige Name des Wochentages (z.B. Sonntag). Abhängig von der aktuell eingestellten Locale.
%b Abgekürzter Name des Monats (z.B. Jan, Feb). Abhängig von der aktuell eingestellten Locale.
%B Der vollständige Name des Monats (z.B. Januar). Abhängig von der aktuell eingestellten Locale.
%c Datum und Uhrzeit in der Formatierung der aktuellen Locale.
%C Das Jahrhunder. Im Prinzip die ersten beiden Stellen der Jahreszahl.
%d Tag im Monat inkl. führender Null. (z.B. 01, 11, etc.).
%D Das aktuelle Datum. Entsprich date +"%m/%d/%y".
%e Tag im Monat. Bei den Tagen 1-9 mit vorangestelltem Leerzeichen. Entsprich %_d.
%F Vollständiges Datum. Entsprich date +"%Y-%m-%d".
%g Die 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.
%G Das 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.
%h Entspricht %b.
%H Stunde im 24-Stunden-Format (00-23).
%I Stunde im 12-Stunden-Format (01-12).
%j Tag des Jahres (001-366).
%k Stunde ohne führende 0 im 24-Stunden-Format (00-23).
%l Stunde ohne führende 0 im 12-Stunden-Format (0-12).
%m Monat mit führender 0 (01-12).
%M Minute mit führender 0 (00-59).
%n Ein Newline-Zeichen (\n).
%N Nanosekunden (000000000..999999999)
%p Darstellung von AM und PM in der lokalen Schreibweise.
%P Wie %p nur in Kleinbuchstaben (nicht ganz logisch - ich weiß)
%r Uhrzeit im 12-Stunden-Format in der lokalen Schreibweise.
%R Uhrzeit im 24-Stunden-Format in der lokalen Schreibweise.
%s Sekunden seit 01.01.1970 00:00:00 Uhr UTC.
%S Sekunden
%t Ein Tab.
%T Uhrzeit im Format %H:%M:%S.
%u Wochentag (1..7). 1 entspricht dem Montag.
%U Wochennummer im Jahr. Dabei wird der Sonntag als erster Tag der Woche angenommen.
%V ISO-konforme Wochennummer (01..53).
%w Wochentag (0..6). 0 entspricht dem Sonntag.
%W Wochennummer im Jahr. Dabei wird der Montag als erster Tag der Woche angenommen.
%x Datumsangabe in der aktuellen, lokalen Schreibweise.
%X Zeitangabe in der aktuellen, lokalen Schreibweise.
%y Die letzten zwei Stellen der Jahreszahl.
%Y Vierstellige Jahreszahl.
%z Zeitzone als nummerische Repräsentation (z.B. +0100 für MEZ).
%:z Zeitzone in der Darstellung Shh:mm (z.B. +01:00 für MEZ).
%::z Zeitzone in der Darstellung Shh:mm:ss (z.B. +01:00:00 für MEZ).
%Z Darstellung 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:

Zeichen Bedeutung
- Das Feld nicht auffüllen.
_ Das Feld mit Leerzeichen auffüllen.
0 Das 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.