Imprime o registro quando a data em um campo está dentro de um mês de outro campo (datas em MM-DD-AAAA)

0

Resumindo, meu principal problema é imprimir um registro quando a data em um campo está dentro de um mês de outro campo . Todas as datas estão no formato MM-DD-AAAA .

Especificamente, estou procurando extrair registros de um arquivo que contém 108 campos delimitados por pipe ( | ), se eles atenderem aos seguintes critérios:

  1. Campo de data 14 & 61 deve ter dados de outubro #Resolvidos

  2. O campo de data 14 deve ser menor que o campo de data 15 + 1mês ($ 15 < $ 14 + 1 mês) #Não resolvido

Meu código:

awk -F'|' '{ if ($14 ~ /10-..-2016/ && $61 ~ /10-..-2016/ && $15< date -d '$14 1 month'  ) print $0}' <input >output

A parte que não está funcionando é $15< date -d '$14 1 month' . O principal problema é o formato MM-DD-YYYY e estou comparando dois campos.

Entrada (não tenho cabeçalhos, usando-os apenas para ajudar a explicar meus dados de amostra. Em negrito a razão para não incluir o registro):
..... | campo14 | campo15 | ..... | Field61 | .....
1 ..... | 10-21-2016 | 11- 23 -2016 | ..... | 10-25-2016 | .....
2 ..... | 10-21-2016 | 11-20-2016 | ..... | 11 -25-2016 | .....
3 ..... | 10-21-2016 | 11-19-2016 | ..... | 10-25-2016 | .....
4 ..... | 10-15-2016 | 11-10-2016 | ..... | 10-25-2016 | .....
5 ..... | 10-21-2016 | 10-19 -2016 | ..... | 10-25-2016 | .....
6 ..... | 09 -21-2016 | 09-19-2016 | ..... | 10-25-2016 | .....
Saída desejável (cabeçalhos usados apenas para explicação):
..... | campo14 | campo15 | ..... | Field61 | .....
3 ..... | 10-21-2016 | 11-19-2016 | ..... | 10-25-2016 | .....
4 ..... | 10-21-2016 | 11-15-2016 | ..... | 10-25-2016 | .....

Como posso corrigir isso?

    
por Greg 29.03.2017 / 20:12

3 respostas

1

perl -F'[|]' -lane '
   ($m2, $d2, $y2, $m1, $d1, $y1) = map { split /-/ } @F[14,13];

   ($m2, $d2, $y2, $m1, $d1, $y1) =
   ($m1, $d1, $y1, $m2, $d2, $y2) if !($y2 > $y1 or $m2 > $m1 or $d2 > $d1);

   print if
      2 == grep /^10-\d{2}-\d{4}$/, @F[13,60]
                and
      (((12*($y2-$y1)+$m2-$m1) == 1 && ($d2 < $d1))
                    ||
          ((12*($y2-$y1)+$m2-$m1) == 0))
' yourfile

Explicação

Nós configuramos um loop de leitura de linha implícito e dividimos cada linha com o pipe '|' delimitador e a arrray @F cujo índice iniciado em 0 é construído.

Em seguida, adicionamos as informações de mês / ano / dia dos campos 14 e 15 nas variáveis escalares para facilitar as manipulações mais adiante no código.

E enquanto estamos nisso, fazemos um ligeiro ajuste para garantir que m2y2d2 date seja sempre mais recente que o m1y1d1 apenas para simplificar nossos cálculos de lógica de data.

Finalmente, decidimos imprimir o registro atual, também conhecido como linha, a julgar por esses quatro critérios, a saber,

  • O 14º elemento, ou seja, $F[13] é uma data de October mês. AND
  • O elemento 61-st, por exemplo, $F[60] , também é uma data% mês October . AND
  • As duas datas são separadas por um mês, o ano foi considerado ao usar o termo (y2-y1)*12 , eles ficam a um mês um do outro quando o dia da data mais alta é < menor dia da data. OU
  • As duas datas são do mesmo ano, mesmo mês = > eles estão dentro de um mês de qualquer maneira.
por 30.03.2017 / 07:47
0

A execução de date para cada linha seria bastante ineficiente, seria melhor usar uma ferramenta de processamento de texto que pudesse calcular a data por si só como perl :

perl -MTime::Piece -F'[|]' -lane 'print if
   $F[13] =~ /10-..-2016/ && 
   $F[60] =~ /10-..-2016/ &&
   Time::Piece->strptime($F[14], "%m-%d-%Y") <
     Time::Piece->strptime($F[13], "%m-%d-%Y")->add_months(1)' file 
    
por 29.03.2017 / 22:20
0

Na verdade, não é tão difícil se você usar GNU awk , que possui funções de tempo integradas:

$2 ~ /^10/ && $5 ~ /^10/ {
    split($2, t, "-");
    t1 = mktime(t[3] " " t[1] " " t[2] " 0 0 0");
    split($3, t, "-");
    t2 = mktime(t[3] " " t[1] " " t[2] " 0 0 0");
    if (t2 >= t1 && t2 - t1 <= 30*24*3600) {
        print;
    }
}
    
por 30.03.2017 / 08:11