Calcular o número de dias para o pagamento

5

Eu preciso mostrar um número de dias para o próximo dia de pagamento (digamos que seja sempre no dia 10 de qualquer mês).

Como faço isso no bash?

    
por Michal Przybylowicz 07.03.2017 / 21:19

4 respostas

4

dom = dia do mês

dom=6 ; \
days=$[ ${dom}-$(date +%-d) ] ; \
[ ${days} -lt 0 ] && days=$[ ${days} + $(date +%d -d "$(date +%Y%m01 -d 'next month') yesterday") ] ; \
echo ${days} days

30 days
    
por 07.03.2017 / 21:28
11

Embora bash agora tenha recursos de formatação de data, ele não tem análise de data ou cálculo, portanto, convém usar outro shell como ksh93 ou zsh ou uma linguagem de programação adequada como perl ou python .

Com ksh93 , a parte difícil é descobrir que formato de data é suportado, pois é dificilmente documentado (você sempre pode dar uma olhada em os dados do teste embora para exemplos).

Por exemplo, ele suporta a especificação do horário do crontab e, em seguida, fornece a próxima vez que corresponde à especificação, para que você possa fazer:

now=$(printf '%(%s)T')
next_10th=$(printf '%(%s)T' '* * 10 * *')

echo "Pay day is in $(((next_10th - now) / 86400)) days"

Agora, com os utilitários padrão, não é tão difícil de implementar:

eval "$(date '+day=%d month=%m year=%Y')"
day=${day#0} month=${month#0}
if [ "$day" -le 10 ]; then
  delta=$((10 - day))
else
  case $month in
    [13578]|10|12) D=31;;
    2) D=$((28 + (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))));;
    *) D=30;;
  esac
  delta=$((D - day + 10))
fi
echo "Pay day is in $delta days"
    
por 07.03.2017 / 22:02
0
echo $(expr '(' $(date -d 2017/03/10 +%s) - $(date +%s) + 86399 ')' / 86400) "days for my payment"
3 days for my payment
    
por 07.03.2017 / 21:26
0

Precisamos apenas subtrair o dia atual (hoje dia $td ) do PayDay esperado selecionado.

Se o PayDay for maior que o dia atual, o resultado será positivo e correto.

Por exemplo, td = 8 e pd = 15:

$ td=8; pd=15
$ echo "The next PayDay will be in $((pd-td)) days"
7

Se o resultado for negativo, basta adicionar o número de dias do mês atual.

O script para executar isso pode ser:

#!/bin/bash

pd=${1:-10}               # Pay day selected
td=$( date -u +'%-d' )    # Today day of the month.

# To calculate the number of days in the present month.
MonthDays=$(  date +'%-d' -ud "$(date +"%Y-%m-01T00:00:00UTC") next month last day"  )
# Maybe a simpler alternative for current month last day:
# echo $(cal) | awk '{print $NF}'     # $(cal) is unquoted on purpose.

# Make the next PayDay fit within the available days in the month.
# If the selected PayDay given to the script is 31 and the month
# only has 30 days, the next PayDay should be 30,
# not an un-existent and impossible 31.
pd=$(( (pd>MonthDays)?MonthDays:pd ))

res=$(( pd-td ))
# If the value of res is negative, just add the number of days in present month.
echo "Pay Day is in $(( res+=(res<0)?MonthDays:0 )) days"    

Observe que o comando exclusivo date precisa usar apenas o mês atual, portanto, nenhum limite de mês / ano foi ultrapassado. Isso evita quase todos os problemas. A única suposição é que o mês atual começa no dia 01 . Além disso, o cálculo é feito em UTC + 0, o que evita possíveis problemas com o horário de verão (DST) ou alterações locais.

Se o PayDay selecionado (Say 31) for maior que o número de dias possíveis no mês (Say February with 28), o programa assume que 28 é o PayDay em vez de um existente (para fevereiro) 31.

Chamando o roteiro (se hoje for o dia 9):

$ ./script 7
Pay Day is in 29 days

$ ./script 16
Pay Day is in 7 days

$ ./script 31
Pay Day is in 19 days

Mas se hoje for dia 28 de fevereiro:

$ ./script 8
Pay Day is in 8 days

$ ./script 28
Pay Day is in 0 days

$ ./script 31
Pay Day is in 0 days
    
por 09.03.2017 / 12:41