data: ottenere l'intervallo attuale di 15 minuti


15

C'è un modo per ottenere l'attuale intervallo di 15 minuti usando il comando data o simile?

ad es. qualcosa come la data %Y.%m.%d %H:%M mi darà 2011.02.22 10:19, ho bisogno di qualcosa che ceda 2011.02.22 10:15nel tempo da 10:15a 10:29.

Risposte:


17

È possibile ottenere il timestamp unix corrente con date "+%s", trovare l'attuale quarto d'ora con alcuni semplici calcoli (il mio esempio è in bash) e stamparlo con un formato migliore con date:

curdate=`date "+%s"`
curquarter=$(($curdate - ($curdate % (15 * 60))))
date -d"@$curquarter"

La @sintassi per impostare la data e l'ora correnti da un timestamp è un'estensione GNU fino ad oggi, se non funziona sul tuo sistema operativo, puoi fare lo stesso in questo modo (non dimenticare di specificare UTC, altrimenti, ha vinto ' t funziona):

date -d"1970-01-01 $curquarter seconds UTC"

5

I seguenti metodi rendono superfluo chiamare datedue volte.
L'overhead di una chiamata di sistema può rendere un comando "semplice" 100 volte più lento di bash facendo la stessa cosa nel proprio ambiente locale.

AGGIORNAMENTO Solo una breve menzione del mio commento sopra: "100 volte più lento". Ora può leggere " 500 volte più lento" ... Di recente sono caduto (no, ho camminato alla cieca) proprio in questo problema. ecco il link: modo rapido per creare un file di prova

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
[[ "$M" < "15" ]] && M=00 # cater for octal clash
M=$(((M/15)*15))
((M==0)) && M=00 # the math returns 0, so make it 00  
echo $Y.$m.$d $H:$M  

o

eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
if   [[ "$M" < "15" ]] ; then M=00
elif [[ "$M" < "30" ]] ; then M=15
elif [[ "$M" < "45" ]] ; then M=30
else M=45
fi
echo $Y.$m.$d $H:$M

Entrambe le versioni restituiranno solo

2011.02.23 01:00
2011.02.23 01:15
2011.02.23 01:30
2011.02.23 01:45   

Ecco il primo con un ciclo TEST per tutti i 60 valori {00..59}

for X in {00..59} ;                         ###### TEST
do                                          ###### TEST 
  eval $(date +Y=%Y\;m=%m\;d=%d\;H=%H\;M=%M)
  M=$X                                      ###### TEST 
  [[ "$M" < "15" ]] && M=00 # cater for octal clash
  M=$(((M/15)*15))
  ((M==0)) && M=00 # the math returns 0, so make it 00  
  echo $Y.$m.$d $H:$M 
done                                        ###### TEST 

1
Solo per chiarimenti: per "chiamata di sistema", si intende "fork / exec / wait, come la chiamata di sistema ()", non la chiamata di sistema in generale. (Ne parlo perché fare chiamate di sistema ha anche un sovraccarico all'interno di un programma, a causa dello switch utente / kernel. Questo non è il problema particolare qui.)
mattdm

mattdm ... Grazie .. Sto lavorando da solo 6 mesi di esperienza Linux, quindi ho probabilmente usato la frase sbagliata, ma continuo a leggere le spese generali sostenute da chiamate non necessarie e nella mia esperienza di test mia script, ho visto molti esempi in cui chiamare printfo sede anche che "inutili" catvs <file fa una differenza drammatica in fase di esecuzione. quando eseguo il looping, come nel mio esempio "500 volte più lento" .. Quindi sembra che usare la shell laddove possibile e consentire un programma come dateun processo batch sia ciò che intendo ... ad es. Esempio Gilles 'Left-Pad-0, vs printf
Peter.O

3

Ecco un modo di lavorare sulle date nella shell. Prima chiamata dateper ottenere i componenti e riempire i parametri posizionali ( $1,$2 , ecc) con i componenti (nota che questo è uno di questi rari casi in cui si desidera utilizzare $(…)al di fuori di virgolette, per rompere la stringa in parole). Quindi eseguire aritmetica, test o qualsiasi altra cosa che si debba fare sui componenti. Infine assemblare i componenti.

La parte aritmetica può essere un po 'complicata perché le conchiglie trattano 0come un prefisso ottale; per esempio qui $(($5/15))fallirebbe dopo 8 o 9 minuti l'ora. Dal momento che c'è al massimo un leader 0, ${5#0}è sicuro per l'aritmetica. L'aggiunta di 100 e la successiva eliminazione di 1è un modo per ottenere un numero fisso di cifre nell'output.

set $(date "+%Y %m %d %H %M")
m=$((100+15*(${5#0}/15)))
last_quarter_hour="$1.$2.$3 $4:${m#1}"

"I trucchi del mestiere" ... buono. :)
Peter

2

Forse non ha più importanza, ma potresti provare le mie date personali . L'arrotondamento (verso il basso) ai minuti viene eseguito con droundun argomento negativo:

dround now /-15m
=>
  2012-07-11T13:00:00

O per aderire al tuo formato:

dround now /-15m -f '%Y.%m.%d %H:%M'
=>
  2012.07.11 13:00

è davvero così che funzionano i tuoi programmi di utilità? usando -15m ottengo l'input riavvolto ai 15 minuti più vicini un'ora: non dateutils.dround '2018-11-12 13:55' -15mproduce . 2018-11-12T13:15:002018-11-12T13:45:00

1
@JackDouglas Gli strumenti si sono evoluti, quello che vuoi ora è: /-15mcioè arrotondare al multiplo successivo di 15 minuti nell'ora. Questa funzione ha la sintassi più ingombrante perché accetta meno valori, / -13m non è possibile ad esempio perché 13 non è un divisore di 60 (minuti nell'ora)
hroptatyr

bello, ho quello che mi serve ora dateutils.dround '2018-11-12 12:52:31' /450s /-15m, grazie!

2

Alcune shell sono in grado di fare il lavoro senza chiamare un datecomando esterno :

a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "#$((a-a%(15*60)))"
a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "$((a-a%(15*60)))"
zmodload zsh/datetime; a=$EPOCHSECONDS; strftime '%Y-%m-%d %H:%M' $((a-a%(15*60)))

I tre sopra forniscono l'ora locale (non UTC). Utilizzare una TZ = UTC0 iniziale, se necessario.

La sintassi ksh e bash è quasi identica (ad eccezione di quella richiesta #in ksh). Zsh richiede di caricare un modulo (incluso con la distribuzione zsh).

È anche possibile farlo con (GNU) awk:

awk 'BEGIN{t=systime();print strftime("%Y.%m.%d %H:%M",t-t%(15*60),1)}'

Questo fornisce un risultato UTC (cambia l'ultimo 1in 0) se è necessario locale. Ma caricare un awk esterno o un modulo zsh esterno potrebbe essere lento quanto la stessa data di chiamata:

a=$(date +%s); date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Un piccolo eseguibile come busybox potrebbe fornire risultati simili:

a=$(busybox date +%s);busybox date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'

Si noti che la parola principale busybox può essere omessa se busybox è collegato a quei nomi in una directory del PERCORSO.

Entrambi datee busybox datesopra stamperanno i tempi UTC. Rimuovi l' -uopzione per l'ora locale.


Se il tuo sistema operativo ha una versione più limitata della data (ed è quello che devi usare) allora prova:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -d"1970-01-01 $a seconds UTC" +'%Y.%m.%d %H:%M'

Oppure, se in FreeBSD, prova:

a=$(date +%s); a=$(( a-a%(15*60) ))
date -r "$a" +'%Y.%m.%d %H:%M'

1

Se riesci a convivere due volte con la data della chiamata, questa funziona in modo basico su Solaris:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))"

Modificato a nome del commento per:

date +"%Y.%m.%d %H:$(( $(date +'%M') / 15 * 15 ))" | sed 's/:0$/:00/'

1
Nel primo trimestre dell'ora, questo produrrà un output dei minuti con un solo 0 anziché 00
Peter.O

Corretto, è un semplice sed dopo il comando originale.
ddeimeke,

Un altro bug: non funziona tra H: 08 e H: 10. Vedi la mia risposta per perché e una soluzione.
Gilles 'SO- smetti di essere malvagio' il

-1

Non sono sicuro del tuo esatto requisito. Tuttavia, se si desidera generare il tempo dopo 15 minuti, è possibile utilizzare qualcosa di simile date -d '+15 min'. L'output è mostrato di seguito:

$ date; date  -d '+15 min'
Tue Feb 22 18:12:39 IST 2011
Tue Feb 22 18:27:39 IST 2011

1
Hai frainteso la domanda. Il punto è arrotondare la data (in basso) a un multiplo di 15 minuti.
Gilles 'SO- smetti di essere malvagio' il
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.