Ferramenta no UNIX para subtrair datas

22

Existe alguma ferramenta no Solaris UNIX (portanto, nenhuma ferramenta GNU disponível) para subtrair datas? Eu sei que no Linux temos gawkque podemos subtrair uma data de outra. Mas no Solaris o máximo que temos é nawk(melhorado awk) que não pode executar cálculos de data. Também não posso usar perl.

Existe alguma maneira de fazer cálculos de datas 20100909 - 20001010?

ATUALIZAÇÃO: É bccapaz de executar cálculos de datas?

jyz
fonte
1
Consulte também Calcular rapidamente as diferenças de data , para quando a data GNU estiver disponível.
Gilles 'SO- stop be evil'

Respostas:

10

Aqui está um script awk que acabei de escrever, deve funcionar com um awix POSIX. Você terá que experimentar a versão Solaris; lembre-se de que também existem duas versões do Awk no Solaris, uma em / bin e outra em / usr / xpg4 / bin / awk (que é nawk, acredito).

BEGIN {
    daysofmonth["01"] = 0; daysofmonth["02"] = 31; daysofmonth["03"] = 59;
    daysofmonth["04"] = 90; daysofmonth["05"] = 120; daysofmonth["06"] = 151;
    daysofmonth["07"] = 181; daysofmonth["08"] = 212; daysofmonth["09"] = 243;
    daysofmonth["10"] = 273; daysofmonth["11"] = 304; daysofmonth["12"] = 334;
    fullday = 86400;
}
/[12][09][0-9][0-9][01][0-9][0123][0-9]/ {
    year = substr($0, 1, 4); month = substr($0, 5, 2); day = substr($0, 7, 2);
    date = ((year - 1970) * 365.25) + daysofmonth[month] + day - 1;
    if ((year % 4) == 0 && month > 2) { date = date + 1; }
    print date * fullday - (25200);
}
{}

Passe uma sequência de datas AAAAMMdd e ela será convertida em número de segundos desde a época (com um pouco de atenção por estar nos limites do dia). Então você poderá subtrair os dois.

today=`echo 20110210 | awk -f convdate.awk`
then=`echo 20001231 | awk -f convdate.awk`
sincethen=`expr $today - $then`
Arcege
fonte
Eu verifiquei sua lógica com o Oracle. Para algumas datas está ok, no entanto, pois gera um número flutuante. Receio que tenho que truncar para um número inteiro, não é?
JYZ
O decimal é a fração de segundo e não é necessariamente necessário.
Arcege 17/02/11
A época expira em 20380119. Por que não usar o dia juliano do ano? Dupe ... unix.stackexchange.com/questions/302266/...
jas-
13

Infelizmente, nenhum dos utilitários de linha de comando POSIX fornece aritmética nas datas. date -de date +%sé o caminho a percorrer, se você os possuir, mas são extensões GNU.

Há um truque desajeitado com touchesse tipo de trabalho para verificar se uma data é pelo menos n dias no passado:

touch -t 201009090000 stamp
if [ -n "$(find stamp -mtime +42)" ]; then ...

(Observe que esse código pode ser desativado em um se o horário de verão tiver sido iniciado ou interrompido no intervalo e o script for executado antes da 01:00.)

Várias pessoas acabaram implementando bibliotecas de manipulação de datas no Bourne ou no POSIX shell. Existem alguns exemplos e links na FAQ do comp.unix.shell .

A instalação de ferramentas GNU pode ser o caminho menos trabalhoso.

Gilles 'SO- parar de ser mau'
fonte
11

Eu tentaria usar o datecomando que faz parte do POSIX, por isso está praticamente em todo lugar. ATUALIZAÇÃO: Infelizmente, parece que -d não faz parte da data POSIX e provavelmente não existe no Solaris. Portanto, isso provavelmente não responderá à pergunta dos OPs.

d1=`date -d 20100909 +%s`
d2=`date -d 20001010 +%s`

Agora d1e d2são números inteiros que correspondem a segundos desde a época do unix. Assim, para obter a diferença entre os dois, subtraímos ( $((d1-d2))no bash) e nos escondemos para as unidades que desejamos. Os dias são os mais fáceis:

echo "$(((d1-d2)/86400)) days"

Como fazer a conversão provavelmente será diferente se você não tiver o bash. A maneira mais portátil pode ser usar expr( página de manual do expr posix ).

Steven D
fonte
sim isso não responder à minha pergunta, porque é Solaris ... mas obrigado pela ideia e postagem :)
JYZ
8

Para constar, dateutils é minha tentativa de fornecer um conjunto de ferramentas portáteis que cobrem a aritmética de datas. Seu exemplo se resume a

ddiff -i '%Y%m%d' 20001010 20100909
=>
  3621

O -iespecifica o formato de entrada.

hroptatyr
fonte
2
Este pacote é incrível e existe nas bibliotecas do universo Ubuntu (pelo menos para Trusty). Em outro sistema, eu poderia compilá-lo facilmente do zero. Altamente recomendado. Muito obrigado!
Robert Muil
Também empacotado no Fedora e no EPEL, para o ecossistema RH.
mattdm
4

É provável que o Perl esteja instalado, e é fácil o suficiente pegar módulos do CPAN , instalá-los no diretório inicial e consultá-los no seu programa. Nesse caso, o módulo Date :: Calc possui uma Delta_Dayssub - rotina que ajudará.

Glenn Jackman
fonte
3

Data do GNU escrita no Solaris:

Eu digo isso de novo:

Muitos Solaris SysAdmins se orgulham de não instalar deliberadamente os pacotes oficiais da Sun (agora Oracle) que tornam um sistema Solaris "compatível com GNU" quando configuram um novo host. Me bate por que.

A Data GNU é excelente e deve estar disponível por padrão em qualquer host Solaris, IMHO.

No Solaris 10

Instale o pacote SFWcoreu a partir do CD do Solaris Companion. Após a instalação, você encontrará a data do GNU em/opt/sfw/bin/date

No Solaris 11

Você já pode tê-lo, pois acredito que faz parte da instalação padrão. No entanto, é chamado gdatepara distingui-lo da versão Sun da data.

Faça isso se não estiver instalado:

pkg install // solaris / file / gnu-coreutils
peterh
fonte
Obrigado pela dica. Você pode me dar um exemplo de como usá-lo? Então eu posso perguntar sysadmin para instalá-lo ...
JYZ
No Solaris 11, ele será instalado como ambos /usr/bin/gdatee, /usr/gnu/bin/dateportanto, você poderá optar por usá-lo pelo nome ou pela configuração $ PATH.
alanc 6/07/2013
2

Se você tem Python:

from time import *
date1 = strptime("20100909","%Y%m%d")
date2 = strptime("20001010","%Y%m%d")
diff = mktime(date1) - mktime(date2)
print repr(d/86400) + " days"

Você marcou sua pergunta como "gawk", mas diz "sem ferramentas GNU". Gawk tem data aritmética.

Pausado até novo aviso.
fonte
Eu não fiz. Alguém editou minha postagem e marcou "gawk" ...
jyz 9/09/10
2

python:

 from datetime import datetime as dt
 a = dt(2010, 9, 9)
 b = dt(2000, 10, 10)
 print (a - b).days
akira
fonte
1

1. Defina data1 e data2 no formato do %jdia do ano (001..366)

user@linux:~$ date1=`date -d 20100909 +%j` 
user@linux:~$ date2=`date -d 20001010 +%j`

2. Calcule a diferença com expr

user@linux:~$ datediff=`expr $date2 - $date1`

3. Então, a resposta é 32 dias

user@linux:~$ echo $datediff days
32 days
user@linux:~$ 

... ou solução de uma linha

user@linux:~$ echo $(( $(date -d 20001010 +%j) - $(date -d 20100909 +%j) )) days
32 days
user@linux:~$ 

ou

user@linux:~$ expr $(date -d 20001010 +%j) - $(date -d 20100909 +%j)
32
user@linux:~$

ou

user@linux:~$ expr `date -d 20001010 +%j` - `date -d 20100909 +%j`
32
user@linux:~$ 
Sabrina
fonte
0

Com a data BSD para macOS:

echo "Quelle est la date de début ?"
read DATE_DE_DEBUT
echo "Quelle est la date de fin ?"
read DATE_DE_FIN
ANNEE=$(($(echo $DATE_DE_FIN | awk -F "/" '{print $3}')-$(echo $DATE_DE_DEBUT  | awk -F "/" '{print $3}')))

echo " "

if [[ $ANNEE > 0 ]]; then

for((annee=$ANNEE-1 ; $ANNEE ; annee++))

  do
  #echo $annee  
  for((mois=0 ; 13 - $mois ; mois++))
      do
  #   echo année:$annee mois:$mois
          for((jour=0 ; 32 - $jour ; jour++))
              do
 #             echo année:$annee mois:$mois jour:$jour
           TEST=$(date -Rjf"%d/%m/%Y" -v +"$annee"y -v +"$mois"m -v +"$jour"d $DATE_DE_DEBUT +"%d/%m/%Y")
           if [[ $TEST = $DATE_DE_FIN ]]; then
                  echo "Différence entre le $DATE_DE_DEBUT et le $DATE_DE_FIN";
                  echo "est de :";
                  echo "$annee année(s) $mois mois $jour jour(s)";
             exit 0;
            fi


          done 
  done
  done

 else 
 annee=0
 for((mois=0 ; 13 - $mois ; mois++))
      do
#      echo année:$annee mois:$mois
          for((jour=0 ; 32 - $jour ; jour++))
              do
              #echo année:$annee mois:$mois jour:$jour
              TEST=$(date -Rjf"%d/%m/%Y" -v +"$annee"y -v +"$mois"m -v +"$jour"d $DATE_DE_DEBUT +"%d/%m/%Y")
              if [[ $TEST = $DATE_DE_FIN ]]; then 
                      echo "Différence entre le $DATE_DE_DEBUT et le $DATE_DE_FIN";
                     echo "est de :";
                     echo "$annee année(s) $mois mois $jour jour(s)";
              exit 0;
              fi
              done
      done

fi
OlivierOR
fonte
0

Você pode usar a biblioteca awk Velour para retornar a diferença em segundos:

$ velour -n 'print t_utc(2010, 9, 9) - t_utc(2000, 10, 10)'
312854400

Ou dias:

$ velour -n 'print t_secday(t_utc(2010, 9, 9) - t_utc(2000, 10, 10))'
3621
Steven Penny
fonte