Holen Sie sich das gestrige Datum in Bash unter Linux, DST-sicher

158

Ich habe ein Shell-Skript, das unter Linux ausgeführt wird und diesen Aufruf verwendet, um das gestrige Datum im YYYY-MM-DDFormat abzurufen:

date -d "1 day ago" '+%Y-%m-%d'

Es funktioniert die meiste Zeit, aber als das Skript gestern Morgen lief 2013-03-11 0:35 CDT, kehrte es "2013-03-09"statt zurück "2013-03-10".

Vermutlich ist die Sommerzeit (die gestern begann) schuld. Ich schätze , dass die Art und Weise "1 day ago"durchgeführt wird 24 Stunden abgezogen und 24 Stunden vor dem 2013-03-11 0:35 CDTwar 2013-03-09 23:35 CST, was zu dem Ergebnis führte "2013-03-09".

Was ist also ein guter DST-sicherer Weg, um das gestrige Datum in Bash unter Linux zu bekommen?

Ike Walker
quelle
Führen Sie dies immer zur gleichen Zeit aus, führen Sie es wiederholt aus?
Tink
@ Tink läuft es täglich um 00:35
Ike Walker

Antworten:

267

Ich denke, das sollte funktionieren, unabhängig davon, wie oft und wann Sie es ausführen ...

date -d "yesterday 13:00" '+%Y-%m-%d'
basteln
quelle
1
Wie würden Sie dies einer Variablen zur späteren Verwendung zuweisen?
null
6
@null - auf die gleiche Weise, wie Sie die Ausgabe eines anderen Shell-Befehls zuweisen würden. Variable = $ (Datum -d "gestern 13:00" '+% Y-% m-% d') ...
Tink
Für GNU-Datum:date -d yesterday 13:00 -I
Gogstad
Dies beruht auf der Tatsache, dass der Wechsel zwischen Sommer- und Winterzeit immer nachts erfolgt, wenn ich das richtig verstehe?
Nicolas Raoul
2
@NicolasRaoul: Es ist nicht garantiert; Es ist jedoch eine weit verbreitete Konvention, dies bis in die frühen Morgenstunden zu planen. Auf der anderen Seite gibt es im IIRC keinen Ort, an dem der Wechsel in der Nähe des lokalen Mittags stattfinden würde. "1300J befindet sich niemals an einer Sommerzeitgrenze" ist also eine vernünftige Annahme .
Piskvor verließ das Gebäude am
56

Datum unter Mac OSX ist etwas anders.

Für gestern

date -v-1d +%F

Für letzte Woche

date -v-1w +%F
Widder
quelle
8
Wenn Sie den GNU-Stil unter OSX verwenden möchten, können Sie ihn auch gdateim Homebrew- coreutilsPaket verwenden.
user456584
11
Du meinst dateist anders.
Augurar
12

Das sollte auch funktionieren, aber vielleicht ist es zu viel:

date -d @$(( $(date +"%s") - 86400)) +"%Y-%m-%d"
perreal
quelle
Solche Sachen werden benötigt, wenn Sie mit Mac OS X arbeiten müssen, datedas keine yesterdaySyntax unterstützt ...
Mikko Rantalainen
7

Wenn Sie sicher sind, dass das Skript in den ersten Stunden des Tages ausgeführt wird, können Sie dies einfach tun

  date -d "12 hours ago" '+%Y-%m-%d'

Übrigens, wenn das Skript täglich um 00:35 Uhr (über crontab?) Ausgeführt wird, sollten Sie sich fragen, was passieren wird, wenn eine DST-Änderung in diese Stunde fällt. Das Skript konnte nicht oder in einigen Fällen zweimal ausgeführt werden. Moderne Implementierungen von cronsind in dieser Hinsicht jedoch ziemlich clever .

leonbloy
quelle
5

Sie können verwenden

date -d "30 days ago" +"%d/%m/%Y"

Um das Datum von vor 30 Tagen zu erhalten, können Sie 30 durch x Tage ersetzen

Dan Pickard
quelle
Sie sollten Ihr Format so ändern, dass %Y%m%des der Frage entspricht. Ich habe trotzdem gestimmt, da es richtig funktioniert hat.
Isapir
4

Hier eine Lösung, die auch mit Solaris und AIX funktioniert.

Das Manipulieren der Zeitzone ist möglich, um die Uhr einige Stunden zu ändern. Aufgrund der Sommerzeit kann 24 Stunden heute oder vorgestern sein.

Sie sind sicher, dass gestern vor 20 oder 30 Stunden war. Welcher? Nun, die jüngste, die es heute nicht gibt.

echo -e "$(TZ=GMT+30 date +%Y-%m-%d)\n$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1

Der im Befehl echo verwendete Parameter -e wird für bash benötigt, funktioniert jedoch nicht mit ksh. In ksh können Sie denselben Befehl ohne das Flag -e verwenden.

Wenn Ihr Skript in verschiedenen Umgebungen verwendet wird, können Sie das Skript mit #! / Bin / ksh oder #! / Bin / bash starten. Sie können das \ n auch durch eine neue Zeile ersetzen:

echo "$(TZ=GMT+30 date +%Y-%m-%d)
$(TZ=GMT+20 date +%Y-%m-%d)" | grep -v $(date +%Y-%m-%d) | tail -1
Walter A.
quelle
0

Verwenden Sie einfach dateund vertrauenswürdige Sekunden:

Wie Sie zu Recht betonen, sind viele Details der zugrunde liegenden Berechnung verborgen, wenn Sie sich auf die englische Zeitarithmetik verlassen. ZB -d yesterdayund -d 1 day agowird ein anderes Verhalten haben.

Stattdessen können Sie sich zuverlässig auf die (genau dokumentierten) Sekunden seit der Unix-Epoche UTC und die Bash-Arithmetik verlassen, um den gewünschten Moment zu erhalten:

date -d @$(( $(date +"%s") - 24*3600)) +"%Y-%m-%d"

Darauf wurde in einer anderen Antwort hingewiesen . Dieses Formular ist plattformübergreifend mit unterschiedlichen dateBefehlszeilenflags portabler, sprachunabhängig (z. B. "gestern" vs "hier" im französischen Gebietsschema) und offen gesagt (auf lange Sicht) leichter zu merken, weil Sie weiß es schon. Sie könnten sich sonst immer wieder fragen: "War es -d 2 hours agooder -d 2 hour agowieder?" oder "Ist es -d yesterdayoder -d 1 day agodas ich will?"). Das einzig schwierige hier ist das @.

Bewaffnet mit Bash und sonst nichts:

Bash nur auf Bash, können Sie auch die gestrige Zeit über die eingebaute printf erhalten:

 %(datefmt)T
     causes printf to output the date-time string resulting from using
     datefmt as a format string for strftime(3).  The  corresponding  argu
     ment  is an integer representing the number of seconds since the
     epoch.  Two special argument values may be used: -1 represents the
     current time, and -2 represents the time the shell was invoked.
     If no argument is specified, conversion behaves as if -1 had
     been  given.
     This is an exception to the usual printf behavior.

So,

# inner printf gets you the current unix time in seconds
# outer printf spits it out according to the format
printf "%(%Y-%m-%d)T\n" $(( $(printf "%(%s)T" -1) - 24*3600 ))

oder äquivalent zu einer temporären Variablen (äußere Unterschale optional, hält aber Umgebungsvariablen sauber).

(
  now=$(printf "%(%s)T" -1);
  printf "%(%Y-%m-%d)T\n" $((now - 24*3600));
)

Hinweis: Obwohl auf der Manpage angegeben ist, dass kein Argument für den %()TFormatierer einen Standardwert -1annimmt, erhalte ich stattdessen eine 0 (danke, Bash-Handbuch Version 4.3.48).

init_js
quelle
0
date -d "yesterday" '+%Y-%m-%d'

So verwenden Sie dies später:

date=$(date -d "yesterday" '+%Y-%m-%d')
suresh Palemoni
quelle
2
Während dieser Code das Problem des OP lösen kann, ist es besser, eine Erklärung beizufügen, wie Ihr Code das Problem des OP behebt. Auf diese Weise können zukünftige Besucher aus Ihrem Beitrag lernen und ihn auf ihren eigenen Code anwenden. SO ist kein Codierungsdienst, sondern eine Ressource für Wissen. Hochwertige, vollständige Antworten untermauern diese Idee und werden eher positiv bewertet. Diese Funktionen sowie die Anforderung, dass alle Beiträge in sich geschlossen sein müssen, sind einige Stärken von SO als Plattform, die uns von Foren unterscheidet. Sie können bearbeiten, um zusätzliche Informationen hinzuzufügen und / oder Ihre Erklärungen durch Quelldokumentation zu ergänzen.
SherylHohman
0

Sie können verwenden:

date -d "yesterday 13:55" '+%Y-%m-%d'

Oder wann immer Sie abrufen möchten, wird per Bash abgerufen.

Für Monat:

date -d "30 days ago" '+%Y-%m-%d'
Daremitsu
quelle
0

Da diese Frage markiert ist "DST sicher"

Und datewenn Sie Fork verwenden, um die implizite Verzögerung zu befehlen, gibt es eine einfache und effizientere Möglichkeit, die integrierte Bash -Funktion zu verwenden:

printf -v tznow '%(%z %s)T' -1
TZ=${tznow% *} printf -v yesterday '%(%Y-%m-%d)T' $(( ${tznow#* } - 86400 ))
echo $yesterday

Dies ist viel schneller auf mehr Systemfreundlicher als zu mit Gabel zu date.

Von V> = 5.0 , es gibt eine neue Variable$EPOCHSECONDS

printf -v tz '%(%z)T' -1
TZ=$tz printf -v yesterday '%(%Y-%m-%d)T' $(( EPOCHSECONDS - 86400 ))
echo $yesterday
F. Hauri
quelle