date: obtenha o intervalo atual de 15 minutos


15

Existe alguma maneira de obter o intervalo atual de 15 minutos usando o comando date ou similar?

por exemplo, algo como data %Y.%m.%d %H:%M me dará 2011.02.22 10:19, eu preciso de algo que produza 2011.02.22 10:15no intervalo de tempo de 10:15até 10:29.

Respostas:


17

Você pode obter o timestamp atual do unix date "+%s", encontrar o quarto de hora atual com algumas contas simples (meu exemplo está em bash) e imprimi-lo com um formato melhor com date:

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

A @sintaxe para definir a data e a hora atuais de um registro de data e hora é uma extensão GNU até o momento. Se não funcionar no seu sistema operacional, você poderá fazer o mesmo assim (não se esqueça de especificar o UTC, caso contrário, ele ganhará ' trabalho):

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

5

Os métodos a seguir tornam desnecessário chamar dateduas vezes.
A sobrecarga de uma chamada de sistema pode tornar um comando "simples" 100 vezes mais lento que o bash, fazendo a mesma coisa em seu próprio ambiente local.

UPDATE Apenas uma menção rápida ao meu comentário acima: "100 vezes mais lento". Agora ele pode ler " 500 vezes mais devagar" ... Recentemente, caí (não, andei cegamente) nessa mesma questão. Aqui está o link: Maneira rápida de criar um arquivo de teste

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  

ou

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

Ambas as versões retornarão apenas

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

Aqui está o primeiro com um loop TEST para todos os 60 valores {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
Apenas para esclarecimento - por "chamada do sistema", você quer dizer "fork / exec / wait, como a chamada system ()", não a chamada do sistema em geral. (Digo isto porque fazer chamadas do sistema também tem uma sobrecarga dentro de um programa, por causa do interruptor de utilizador / kernel Essa não é a questão específica aqui..)
mattdm

mattdm ... Obrigado .. Estou trabalhando com apenas 6 meses de experiência no Linux, então provavelmente usei a frase errada, mas continuo lendo sobre as despesas gerais decorrentes de chamadas desnecessárias e na minha própria experiência de testar minhas próprias scripts, já vi muitos exemplos em que chamar printfou sede também que o catarquivo vs < "desnecessário" faz uma diferença drástica no tempo de execução. ao fazer um loop, como no meu exemplo "500 vezes mais lento" .. Parece que usar o shell sempre que possível e permitir que um programa como o dateprocesso em lote seja o que quero dizer .. por exemplo. Exemplo de Left-Pad-0 de Gilles, vs printf
Peter.O

3

Aqui está uma maneira de trabalhar com datas no shell. Primeira chamada datepara obter os componentes e preencher os parâmetros posicionais ( $1, $2etc) com os componentes (observe que esse é um desses casos raros em que você deseja usar $(…)fora de aspas duplas, para dividir a sequência em palavras). Em seguida, execute aritmética, testes ou o que você precisar fazer nos componentes. Finalmente monte os componentes.

A parte aritmética pode ser um pouco complicada porque as conchas são tratadas 0como um prefixo octal; por exemplo, aqui $(($5/15))falharia 8 ou 9 minutos após a hora. Como há no máximo uma liderança 0, ${5#0}é seguro para aritmética. Adicionar 100 e subsequentemente remover o 1é uma maneira de obter um número fixo de dígitos na saída.

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

"Os truques do comércio" ... um bom. :)
Peter.O

2

Talvez isso não importe mais, mas você pode tentar meus próprios dateutils . O arredondamento (para baixo) para minutos é feito com drounde um argumento negativo:

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

Ou para aderir ao seu formato:

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

é assim que seus utils funcionam mais? usando -15m, eu recebo a entrada rebobinada nos 15 minutos passados ​​uma hora mais próximos: não dateutils.dround '2018-11-12 13:55' -15mproduz . 2018-11-12T13:15:002018-11-12T13:45:00

1
@JackDouglas As ferramentas evoluíram, o que você deseja é agora:, /-15mou seja, arredondar para o próximo múltiplo de 15 minutos na hora. Esta característica tem a sintaxe mais complicado porque aceita valores menos, / -13m não é possível, por exemplo, porque 13 não é um divisor de 60 minutos (no horas)
hroptatyr

bom, eu consigo o que preciso agora dateutils.dround '2018-11-12 12:52:31' /450s /-15m, obrigado!

2

Algumas conchas são capazes de fazer o trabalho sem chamar um date comando :

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

Os três acima fornecem a hora local (não UTC). Use um TZ inicial = UTC0, se necessário.

A sintaxe ksh e bash é quase idêntica (exceto as necessárias # no ksh). O zsh requer o carregamento de um módulo (incluído na distribuição zsh).

Também é possível fazer isso com o (GNU) awk:

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

Isso fornece um resultado UTC (altere o último 1para0 ) se local for necessário. Mas carregar um awk externo ou um módulo zsh externo pode ser tão lento quanto a própria data de chamada:

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

Um pequeno executável como busybox poderia fornecer resultados semelhantes:

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

Observe que a palavra principal do busybox pode ser omitida se o busybox estiver vinculado a esses nomes em um diretório do PATH.

Ambos datee busybox dateacima imprimirão os horários UTC. Remova a -uopção para horários locais.


Se o seu sistema operacional tiver uma versão mais limitada da data (e é isso que você deve usar), tente:

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

Ou, se estiver no FreeBSD, tente:

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

1

Se você pode conviver com a data da chamada duas vezes, esta funciona no bash no Solaris:

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

Editado em nome do comentário para:

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

1
No primeiro quarto de hora, isso produzirá uma saída de minutos com apenas um único 0 em vez de 00
Peter.O

Corrigido, é um simples sed após o comando original.
23611 ddeimeke

Mais um bug: não funciona entre H: 08 e H: 10. Veja minha resposta para saber por que e uma correção.
Gilles 'SO- stop be evil'

-1

Não tenho certeza sobre sua exigência exata. No entanto, se você quiser gerar o tempo após 15 minutos, poderá usar algo parecido date -d '+15 min'. A saída é mostrada abaixo:

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

1
Você entendeu mal a pergunta. O ponto é arredondar a data (para baixo) para um múltiplo de 15 minutos.
Gilles 'SO- stop be evil'
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.