it-swarm.com.de

Erhalten Sie das gestrige Datum in bash unter Linux, DST-sicher

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

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

Meistens funktioniert es, aber wenn das Skript gestern morgen um 2013-03-11 0:35 CDT lief, wurde "2013-03-09" anstelle von "2013-03-10" zurückgegeben.

Vermutlich ist die Sommerzeit (die gestern begann) schuld. Ich denke, die Art und Weise, wie "1 day ago" implementiert wird, wurde 24 Stunden abgezogen, und 24 Stunden bevor 2013-03-11 0:35 CDT2013-03-09 23:35 CST war, wurde das Ergebnis "2013-03-09".

Was ist also eine gute DST-sichere Methode, um das gestrige Datum in bash unter Linux zu erhalten?

124
Ike Walker

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

date -d "yesterday 13:00" '+%Y-%m-%d'
203
tink

Bash unter Mac OSX ist etwas anders.

Für gestern

echo `date -v-1d +%F`

Für letzte Woche

echo `date -v-1w +%F`
42
Aries

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

date -d @$(( $(date +"%s") - 86400)) +"%Y-%m-%d"
11
perreal

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 passiert, wenn eine Änderung der Sommerzeit in diese Stunde fällt. Das Skript konnte nicht oder in einigen Fällen zweimal ausgeführt werden. Moderne Implementierungen von cron sind ziemlich klug diesbezüglich jedoch.

4
leonbloy

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

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

Sie sind sicher, dass gestern vor 20 oder 30 Stunden ist. Welcher? Nun, das letzte, das heute nicht ist.

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
3
Walter A

sie können verwenden

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

um das Datum vor 30 Tagen zu erhalten, können Sie 30 durch x Anzahl der Tage ersetzen

2
Dan Pickard

Benutze einfach date und vertraute Sekunden:

Wie Sie zu Recht darauf hinweisen, sind viele Details über die zugrunde liegende Berechnung verborgen, wenn Sie sich auf die englische Zeitarithmetik verlassen. Z.B. -d yesterday und -d 1 day ago verhalten sich unterschiedlich.

Stattdessen können Sie sich zuverlässig auf die (genau dokumentierten) Sekunden seit Unix Epoch 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 auf Plattformen mit unterschiedlichen date-Befehlszeilenflags portabler, es ist sprachunabhängig (z. B. "gestern" vs. "hier" in Französisch), und ehrlich gesagt (langfristig) ist es leichter zu merken, weil du weißt es schon. Sie könnten sich sonst immer wieder fragen: "War es wieder -d 2 hours ago oder -d 2 hour ago?" oder "Ist es -d yesterday oder -d 1 day ago, die ich möchte?"). Das einzige knifflige Bit hier ist der @.

Mit Bash bewaffnet und sonst nichts:

Wenn Sie sich nur auf bash konzentrieren, können Sie auch die gestrige Zeit über das 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: Trotz der Manpage, die besagt, dass kein Argument für den %()T-Formatter einen Standard--1 annehmen wird, scheine ich stattdessen eine 0 zu erhalten (danke, Bash-Handbuchversion 4.3.48)}

0
init_js