A resposta certa ainda está faltando:
todate=$(date -d 2013-07-18 +%s)
cond=$(date -d 2014-08-19 +%s)
if [ $todate -ge $cond ];
then
break
fi
Como duas datas podem ser comparadas em um shell?
Aqui está um exemplo de como eu gostaria de usar isso, embora não funcione como está:
todate=2013-07-18
cond=2013-07-15
if [ $todate -ge $cond ];
then
break
fi
Como posso alcançar o resultado desejado?
A resposta certa ainda está faltando:
todate=$(date -d 2013-07-18 +%s)
cond=$(date -d 2014-08-19 +%s)
if [ $todate -ge $cond ];
then
break
fi
Está faltando o formato de data para a comparação:
#!/bin/bash
todate=$(date -d 2013-07-18 +"%Y%m%d") # = 20130718
cond=$(date -d 2013-07-15 +"%Y%m%d") # = 20130715
if [ $todate -ge $cond ]; #put the loop where you need it
then
echo 'yes';
fi
Você também está perdendo estruturas em loop, como você planeja obter mais datas?
Pode usar uma comparação de string padrão para comparar a ordem cronológica [de strings em um formato de ano, mês e dia].
date_a=2013-07-18
date_b=2013-07-15
if [[ "$date_a" > "$date_b" ]] ;
then
echo "break"
fi
Felizmente, quando as [strings que usam o formato YYYY-MM-DD] são classificadas * em ordem alfabética, elas também são classificadas * em ordem cronológica.
(* - classificado ou comparado)
Nada sofisticado necessário neste caso. yay!
Este não é um problema de estruturas em loop, mas de tipos de dados.
Essas datas ( todate
e cond
) são strings, não números, portanto, você não pode usar o operador "-ge" de test
. (Lembre-se que a notação de colchetes é equivalente ao comando test
.)
O que você pode fazer é usar uma notação diferente para as datas, para que sejam números inteiros. Por exemplo:
date +%Y%m%d
produzirá um inteiro como 20130715 para 15 de julho de 2013. Depois, você poderá comparar suas datas com "-ge" e operadores equivalentes.
Atualização: se suas datas forem informadas (por exemplo, você as está lendo em um arquivo no formato 2013-07-13), você poderá pré-processá-las facilmente com tr.
$ echo "2013-07-15" | tr -d "-"
20130715
O operador -ge
só funciona com números inteiros, o que não é o caso das suas datas.
Se o seu script for bash ou ksh ou zsh, você poderá usar o operador <
. Este operador não está disponível em traços ou outros shells que não vão muito além do padrão POSIX.
if [[ $cond < $todate ]]; then break; fi
Em qualquer shell, você pode converter as strings em números, respeitando a ordem das datas simplesmente removendo os traços.
if [ "$(echo "$todate" | tr -d -)" -ge "$(echo "$cond" | tr -d -)" ]; then break; fi
Como alternativa, você pode se tornar tradicional e usar o utilitário expr
.
if expr "$todate" ">=" "$cond" > /dev/null; then break; fi
Como invocar subprocessos em um loop pode ser lento, você pode preferir fazer a transformação usando construções de processamento de string do shell.
todate_num=${todate%%-*}${todate#*-}; todate_num=${todate_num%%-*}${todate_num#*-}
cond_num=${cond%%-*}${cond#*-}; cond_num=${cond_num%%-*}${cond_num#*-}
if [ "$todate_num" -ge "$cond_num" ]; then break; fi
Claro, se você puder recuperar as datas sem os hífens, poderá compará-las com -ge
.
Eu converto os Strings em unix-timestamps (segundos desde 1.1.1970 0: 0: 0). Estes podem comparar facilmente
unix_todate=$(date -d "${todate}" "+%s")
unix_cond=$(date -d "${cond}" "+%s")
if [ ${unix_todate} -ge ${unix_cond} ]; then
echo "over condition"
fi
Existe também este método no artigo intitulado: Data simples e calculo de tempo no BASH do unix.com.
Estas funções são um trecho de um script nesse tópico!
date2stamp () {
date --utc --date "$1" +%s
}
dateDiff (){
case $1 in
-s) sec=1; shift;;
-m) sec=60; shift;;
-h) sec=3600; shift;;
-d) sec=86400; shift;;
*) sec=86400;;
esac
dte1=$(date2stamp $1)
dte2=$(date2stamp $2)
diffSec=$((dte2-dte1))
if ((diffSec < 0)); then abs=-1; else abs=1; fi
echo $((diffSec/sec*abs))
}
# calculate the number of days between 2 dates
# -s in sec. | -m in min. | -h in hours | -d in days (default)
dateDiff -s "2006-10-01" "2006-10-31"
dateDiff -m "2006-10-01" "2006-10-31"
dateDiff -h "2006-10-01" "2006-10-31"
dateDiff -d "2006-10-01" "2006-10-31"
dateDiff "2006-10-01" "2006-10-31"
datas são strings, não inteiros; você não pode compará-los com operadores aritméticos padrão.
uma abordagem que você pode usar, se o separador for garantido como -
:
IFS=-
read -ra todate <<<"$todate"
read -ra cond <<<"$cond"
for ((idx=0;idx<=numfields;idx++)); do
(( todate[idx] > cond[idx] )) && break
done
unset IFS
Isso funciona desde bash 2.05b.0(1)-release
.
Você também pode usar a função interna do mysql para comparar as datas. Dá o resultado em 'dias'.
from_date="2015-01-02"
date_today="2015-03-10"
diff=$(mysql -u${DBUSER} -p${DBPASSWORD} -N -e"SELECT DATEDIFF('${date_today}','${from_date}');")
Basta inserir os valores das variáveis $DBUSER
e $DBPASSWORD
de acordo com o seu.
Como gosto de reduzir garfos e bash permitem muitas truques, existe o meu propósito:
todate=2013-07-18
cond=2013-07-15
Bem, agora:
{ read todate; read cond ;} < <(date -f - +%s <<<"$todate"$'\n'"$cond")
Isso irá repopular as duas variáveis $todate
e $cond
, usando apenas uma bifurcação, com a exceção de date -f -
, o que leva stdio para ler uma data por linha.
Finalmente, você pode quebrar o seu loop com
((todate>=cond))&&break
Ou como uma função :
myfunc() {
local todate cond
{ read todate
read cond
} < <(
date -f - +%s <<<"$1"$'\n'"$2"
)
((todate>=cond))&&return
printf "%(%a %d %b %Y)T older than %(%a %d %b %Y)T...\n" $todate $cond
}
Usando o bash embutiu printf
, o que poderia renderizar a data com segundos de epoch (veja man bash
; -)
Esse script usa apenas um fork.
FWIW: no Mac, parece que alimentar apenas uma data como "2017-05-05" em data adicionará a hora atual à data e você obterá um valor diferente a cada vez que convertê-la em hora de época. para obter um horário de época mais consistente para datas fixas, inclua valores fictícios para horas, minutos e segundos:
date -j -f "%Y-%m-%d %H:%M:%S" "2017-05-05 00:00:00" +"%s"
Isso pode ser uma peculiaridade limitada à versão da data fornecida com o macOS .... testado no macOS 10.12.6.
Tags date shell shell-script