File: zzdata2.sh

package info (click to toggle)
funcoeszz 21.1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, bullseye, forky, sid, trixie
  • size: 4,424 kB
  • sloc: sh: 27,355; perl: 509; xml: 54; makefile: 8
file content (226 lines) | stat: -rw-r--r-- 6,278 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
# ----------------------------------------------------------------------------
# Faz calculos com datas e/ou converte data->num e num->data.
# Que dia vai ser daqui 45 dias? Quantos dias ha entre duas datas? zzdata!
# Quando chamada com apenas um parametro funciona como conversor de data
# para numero inteiro (N dias passados desde Epoch) e vice-versa.
# A zzdata pode subtrair, ou somar meses e anos tambem. Eh so especificar!
# Obs.: Leva em conta os anos bissextos     (Epoch = 01/01/1970, editavel)
# Opcoes:
#         data|num  data inicial.
#         +|-       operacao a realizar (adicao|subtracao).
#         D|M|Y     unidade em operacao com numero (D=dia, M=mes, Y=ano).
# Uso: zzdata2 data|num [+|- data|num [D|M|Y]]
# Ex.: zzdata2 22/12/1999 + 69
#      zzdata2 hoje - 5
#      zzdata2 01/03/2000 - 11/11/1999
#      zzdata2 hoje - dd/mm/aaaa         <---- use sua data de nascimento
#      zzdata2 01/03/2000 - 1 M          # subtrai 1 mes. resp: 01/02/2000
#      zzdata2 30/03/2008 - 1 M          # resp: 19/02/2008 (ano bissexto)
#
# Autor: Aurélio Marinho Jargas, www.aurelio.net, modificada por Lauro de Sá
# Desde: 2010-05-26
# Versão: 20091010
# Licença: GPLv2
# ----------------------------------------------------------------------------
# DESATIVADA: 2011-05-19 Funcionalidades implementadas na zzdata original.
zzdata2 ()
{
	zzzz -h data2 $1 && return

	local yyyy mm dd dias_ano data dias i n y op muda_ano
	local epoch=1970
	local primeira_data=1
	local dias_mes='31 28 31 30 31 30 31 31 30 31 30 31'
	local data1=$1
	local operacao=$2
	local data2=$3
	local n1=$data1
	local n2=$data2
	local tipo=$4
	
	# Verificacao dos parametros
	# Alterado o numero de parametros para ate 4.
	# Porem, para manter a compatibilidade com versoes anteriores, aceita-se 3.
	# Ou seja, para somar ou subtrair dias nao precisa informar "d".
	[ $# -eq 3 -o $# -eq 1 -o $# -eq 4 ] || { zztool uso data2; return 1; }

	# Esse bloco gigante define $n1 e $n2 baseado nas datas $data1 e $data2.
	# A data eh transformada em um numero inteiro (dias desde $epoch).
	# Exemplo: 27/07/2007 -> 13721
	# Este eh numero usado para fazer os calculos.
	for data in $data1 $data2
	do
		dias=0 # Guarda o total que ira para $n1 e $n2
		
		# Atalhos uteis para o dia atual
		if [ "$data" = 'hoje' -o "$data" = 'today' ]
		then
			# Qual a data de hoje?
			data=$(date +%d/%m/%Y)
			[ "$primeira_data" ] && data1=$data || data2=$data
		else
			# Valida o formato da data
			if ! ( zztool testa_data "$data" || zztool testa_numero "$data" )
			then
				echo "Data invalida '$data', deve ser dd/mm/aaaa"
				return 1
			fi
		fi
		
		# Se tem /, entao e uma data e deve ser transformado em numero
		if zztool grep_var / "$data"
		then
			n=1
			y=$epoch
			yyyy=${data##*/}
			mm=${data#*/}
			mm=${mm%/*}
			dd=${data%%/*}

			# Retira o zero dos dias e meses menores que 10
			mm=${mm#0}
			dd=${dd#0}

			# Define qual sera a operacao: adicao ou subtracao
			op=+
			[ $yyyy -lt $epoch ] && op=-
			
			# Ano -> dias
			while :
			do
				# Sim, os anos bissextos sao levados em conta!
				dias_ano=365
				zztool testa_ano_bissexto ${y} && dias_ano=366
				
				# Vai somando (ou subtraindo) ate chegar no ano corrente
				[ $y -eq $yyyy ] && break
				dias=$((dias $op dias_ano))
				y=$((y $op 1))
			done
			
			# Meses -> dias
			for i in $dias_mes
			do
				[ $n -eq $mm ] && break
				n=$((n+1))
				
				# Fevereiro de ano bissexto tem 29 dias
				[ $dias_ano -eq 366 -a $i -eq 28 ] && i=29
				
				dias=$((dias+$i))
			done
			
			# Somando os dias da data aos anos+meses ja contados (-1)
			dias=$((dias+dd-1))
			
			[ "$primeira_data" ] && n1=$dias || n2=$dias
			
		else
			# Esta parte eh responsavel pela subtracao de meses ou anos.
			# Para isto, o usuario deve informar o terceiro parametro
			# como um numero.
			if [ "$primeira_data" != 1 ] ; then
				# Determinando o tipo de operacao (dia, mes, ou ano)
				case "${tipo}" in
					"m" | "M" | "y" | "Y")
						data2=`zzdata "$n1"`
						dd=`echo "$data2" | cut -c1-2`
						mm=`echo "$data2" | cut -c4-5`
						yyyy=`echo "$data2" | cut -c7-10`
						i=1
						while [ $i -le $n2 ]
						do
							case "${tipo}" in
							"m" | "M")
								muda_ano=1
								[ $mm -eq 1  -a "$operacao" = "-" ] && muda_ano=0 mm="12"
								[ $mm -eq 12 -a "$operacao" = "+" ] && muda_ano=0 mm="01"
								
								if [ "$muda_ano" = 1 ] ; then
									mm=`expr $mm $operacao 1`
									[ $mm -lt 10 ] && mm="0$mm"
								else
									yyyy=`expr $yyyy $operacao 1`
								fi
								;;
							"y" | "Y")	yyyy=`expr $yyyy $operacao 1`;;
							esac
							i=$((i+1))
						done
						
						# Verifica mes de fevereiro.
						if [ $mm -eq 2 -a $dd -gt 28 ] ; then
							zztool testa_ano_bissexto "$yyyy" && dd="29" || dd="28"
						fi
						
						# Verifica se o dia 31 existe no mes.
						if [ $dd -eq 31 ] ; then
							case "${mm}" in
								"04" | "06" | "09" | "11") dd="30";;
							esac
						fi
						
						data1="$dd/$mm/$yyyy"
						n1=`zzdata "$data1"`
						data2=0
						n2=0
						;;
				esac
			fi
		fi
		primeira_data=
	done
	

	
	# Agora que ambas as datas sao numeros inteiros, a conta e feita
	dias=$(($n1 $operacao $n2))
	
	# Se as duas datas foram informadas como dd/mm/aaaa,
	# o resultado e o proprio numero de dias, entao terminamos.
	if [ "${data1##??/*}" = "${data2##??/*}" ]
	then
		echo $dias
		return
	fi
	
	# Como nao caimos no IF anterior, entao o resultado sera uma data.
	# e preciso converter o numero inteiro para dd/mm/aaaa.
	
	y=$epoch
	mm=1
	dd=$((dias+1))
	
	# Dias -> Ano
	while :
	do
		# Novamente, o ano bissexto e levado em conta
		dias_ano=365
		zztool testa_ano_bissexto ${y} && dias_ano=366
		
		# Vai descontando os dias de cada ano para saber quantos anos cabem
		[ $dd -le $dias_ano ] && break
		dd=$((dd-dias_ano))
		y=$((y+1))
	done
	yyyy=$y
	
	# Dias -> mes
	for i in $dias_mes
	do
		# Fevereiro de ano bissexto tem 29 dias
		[ $dias_ano -eq 366 -a $i -eq 28 ] && i=29
	
		# Calcula quantos meses cabem nos dias que sobraram
		[ $dd -le $i ] && break
		dd=$((dd-i))
		mm=$((mm+1))
	done
	
	# Restaura o zero dos meses menores que 10
	[ $dd -le 9 ] && dd=0$dd
	[ $mm -le 9 ] && mm=0$mm
	
	# E finalmente mostra o resultado em formato de data
	echo $dd/$mm/$yyyy
}