Respostas:
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"
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
ou sed
e também que o cat
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 o date
processo em lote seja o que quero dizer .. por exemplo. Exemplo de Left-Pad-0 de Gilles, vs printf
Aqui 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ç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}"
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:
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
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)
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
e busybox 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:
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'
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/'
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