Os métodos a seguir tornam desnecessário chamar date
duas 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
printf
oused
e também que ocat
arquivo 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 odate
processo em lote seja o que quero dizer .. por exemplo. Exemplo de Left-Pad-0 de Gilles, vs printfAqui está uma maneira de trabalhar com datas no shell. Primeira chamada
date
para obter os componentes e preencher os parâmetros posicionais ($1
,$2
etc) 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
0
como um prefixo octal; por exemplo, aqui$(($5/15))
falharia 8 ou 9 minutos após a hora. Como há no máximo uma liderança0
,${5#0}
é seguro para aritmética. Adicionar 100 e subsequentemente remover o1
é uma maneira de obter um número fixo de dígitos na saída.fonte
Talvez isso não importe mais, mas você pode tentar meus próprios dateutils . O arredondamento (para baixo) para minutos é feito com
dround
e um argumento negativo:Ou para aderir ao seu formato:
fonte
dateutils.dround '2018-11-12 13:55' -15m
produz .2018-11-12T13:15:00
2018-11-12T13:45:00
/-15m
ou 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)dateutils.dround '2018-11-12 12:52:31' /450s /-15m
, obrigado!Algumas conchas são capazes de fazer o trabalho sem chamar um
date
comando :ksh
a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "#$((a-a%(15*60)))"
bash
a=$(printf '%(%s)T\n'); printf '%(%Y.%m.%d %H:%M)T\n' "$((a-a%(15*60)))"
zsh
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:
gawk
awk 'BEGIN{t=systime();print strftime("%Y.%m.%d %H:%M",t-t%(15*60),1)}'
Isso fornece um resultado UTC (altere o último
1
para0
) 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:gnu-date
a=$(date +%s); date -ud "@$((a-a%(15*60)))" +'%Y.%m.%d %H:%M'
Um pequeno executável como
busybox
poderia fornecer resultados semelhantes:busybox-date
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
date
ebusybox date
acima imprimirão os horários UTC. Remova a-u
opçã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:
Ou, se estiver no FreeBSD, tente:
fonte
Se você pode conviver com a data da chamada duas vezes, esta funciona no bash no Solaris:
Editado em nome do comentário para:
fonte
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:fonte