Ricevi la data di ieri in bash su Linux, DST-safe


158

Ho uno script di shell che gira su Linux e usa questa chiamata per ottenere la data di ieri in YYYY-MM-DDformato:

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

Funziona quasi sempre, ma quando lo script è stato eseguito ieri mattina 2013-03-11 0:35 CDTè tornato "2013-03-09"invece di "2013-03-10".

Presumibilmente la colpa è dell'ora legale (iniziata ieri). Sto cercando di indovinare il modo in cui "1 day ago"viene implementato è sottratto 24 ore e 24 ore prima 2013-03-11 0:35 CDTera 2013-03-09 23:35 CST, che ha portato al risultato di "2013-03-09".

Allora, qual è un buon modo sicuro per l'ora legale per ottenere la data di ieri in bash su Linux?


Lo esegui sempre allo stesso tempo, lo esegui ripetutamente?
tink

@tink funziona tutti i giorni alle 00:35
Ike Walker

Risposte:


267

Penso che dovrebbe funzionare, indipendentemente da quanto spesso e quando lo esegui ...

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

1
Come lo assegnereste a una variabile da utilizzare in seguito?
null

6
@null - allo stesso modo in cui assegneresti l'output di qualsiasi altro comando shell. variabile = $ (data -d "ieri 13:00" '+% Y-% m-% d') ...
tink

Per GNU-date:date -d yesterday 13:00 -I
gogstad

Ciò si basa sul fatto che il passaggio tra l'ora legale e quella invernale viene sempre effettuato di notte, se ho capito bene?
Nicolas Raoul,

2
@NicolasRaoul: non è garantito; ma è una convenzione ampiamente seguita programmare questo nelle prime ore del mattino. D'altra parte, non c'è IIRC in nessun posto dove l'interruttore potrebbe avvenire vicino a mezzogiorno locale. Pertanto, "1300J non è mai al limite dell'ora legale" è un presupposto ragionevole .
Piskvor lasciò l'edificio il

56

la data in Mac OSX è leggermente diversa.

Per ieri

date -v-1d +%F

Per la scorsa settimana

date -v-1w +%F

8
Se sei interessato ad usare lo stile GNU in OSX, puoi anche usare gdate, disponibile all'interno del coreutilspacchetto homebrew .
user456584,

11
Vuoi dire che dateè diverso.
agosto

12

Anche questo dovrebbe funzionare, ma forse è troppo:

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

Sono necessarie cose del genere se è necessario gestire Mac OS X dateche non supporta la yesterdaysintassi ...
Mikko Rantalainen,

7

Se sei sicuro che lo script verrà eseguito nelle prime ore del giorno, puoi semplicemente farlo

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

A proposito, se lo script viene eseguito ogni giorno alle 00:35 (tramite crontab?) Dovresti chiederti cosa accadrà se un cambio di ora legale cade in quell'ora; lo script non può essere eseguito o eseguito due volte in alcuni casi. Tuttavia, le implementazioni moderne cronsono piuttosto intelligenti in questo senso.


5

Puoi usare

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

per ottenere la data di 30 giorni fa, allo stesso modo è possibile sostituire 30 con x quantità di giorni


È necessario modificare il formato in modo %Y%m%dche corrisponda alla domanda. Ho comunque votato come funzionava correttamente.
Isapir,

4

Qui una soluzione che funzionerà anche con Solaris e AIX.

La manipolazione del fuso orario è possibile per cambiare l'orologio alcune ore. A causa dell'ora legale, 24 ore fa possono essere oggi o l'altro ieri.

Sei sicuro che ieri sono state 20 o 30 ore fa. Quale? Bene, quello più recente che non è oggi.

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

Il parametro -e usato nel comando echo è necessario con bash, ma non funzionerà con ksh. In ksh puoi usare lo stesso comando senza il flag -e.

Quando lo script verrà utilizzato in diversi ambienti, è possibile avviare lo script con #! / Bin / ksh o #! / Bin / bash. Puoi anche sostituire \ n con una nuova riga:

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

0

Basta usare datee secondi fidati:

Come giustamente fai notare, molti dettagli sul calcolo sottostante sono nascosti se fai affidamento sull'aritmetica del tempo inglese. Ad esempio -d yesterday, e -d 1 day agoavrà un comportamento diverso.

Invece, puoi affidarti in modo affidabile ai secondi (documentati con precisione) dai tempi dell'UNIX epoca UTC e bash aritmetica per ottenere il momento desiderato:

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

Questo è stato sottolineato in un'altra risposta . Questo modulo è più portabile su più piattaforme con diversi dateflag della riga di comando, è indipendente dalla lingua (ad es. "Ieri" vs "hier" in locale francese) e francamente (a lungo termine) sarà più facile da ricordare, perché anche tu lo so già. Altrimenti potresti continuare a chiederti: "Era -d 2 hours agoo di -d 2 hour agonuovo?" o "È -d yesterdayo -d 1 day agoquello che voglio?"). L'unico aspetto difficile qui è il @.

Armato di bash e nient'altro:

Bash solo su bash, puoi anche ottenere l'ora di ieri, tramite il printf incorporato:

 %(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.

Così,

# 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 ))

o, equivalentemente con una variabile temp (subshell esterno opzionale, ma mantiene pulite le variabili d'ambiente).

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

Nota: nonostante la manpage affermi che nessun argomento per il %()Tformatter assumerà un valore predefinito -1, mi sembra di ottenere invece uno 0 (grazie, manuale di Bash versione 4.3.48)


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

Per usarlo in seguito:

date=$(date -d "yesterday" '+%Y-%m-%d')

2
Sebbene questo codice possa risolvere il problema del PO, è meglio includere una spiegazione su come il codice risolve il problema del PO. In questo modo, i futuri visitatori possono imparare dal tuo post e applicarlo al proprio codice. SO non è un servizio di codifica, ma una risorsa per la conoscenza. Risposte complete di alta qualità rafforzano questa idea e hanno maggiori probabilità di essere votate. Queste caratteristiche, oltre alla necessità che tutti i post siano autonomi, sono alcuni punti di forza di SO come piattaforma che ci differenzia dai forum. È possibile modificare per aggiungere ulteriori informazioni e / o integrare le proprie spiegazioni con la documentazione di origine.
SherylHohman,

0

Puoi usare:

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

O in qualunque momento tu voglia recuperare sarà recuperato da bash.

Per mese:

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

0

Poiché questa domanda è taggata "Ora legale sicura"

E usando fork per datecomandare il ritardo implie, c'è un modo semplice ed efficiente che usa puro bash incorporato:

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

Questo è molto più veloce su più di agevole di dover sborsare per date.

A partire dal V> = 5.0 , c'è una nuova variabile$EPOCHSECONDS

printf -v tz '%(%z)T' -1
TZ=$tz printf -v yesterday '%(%Y-%m-%d)T' $(( EPOCHSECONDS - 86400 ))
echo $yesterday
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.