Manipulação e Precedência de Data em Cascata [duplicado]

0
echo 20171231 | xargs -i date -d "{} +1 day" | xargs -i date -d "{} -1 month"
**Fri Dec  1 00:00:00 PST 2017**

Nesse caso, quando os comandos de formatação de data são canalizados, recebo 1 de dezembro.

echo 20171231 | xargs -i date -d "{}  +1day -1 month"
Sat Dec  2 00:00:00 PST 2017 

Considerando que a formatação de data está incluída em um único comando de dados recebendo resultado como 2 de dezembro.

No comando acima, parece que -1 mês está ficando acima de +1 dia.

Alguém pode me ajudar a entender como isso funciona?

    
por Murali Rao 08.02.2018 / 21:47

3 respostas

2

Não, não há ordem de precedência.

Ironicamente, isso só surgiu na lista de discussão dos usuários do Debian este mês, onde foi apontado que para um ser humano lendo a suposta linguagem humana legível a manipulação da data natural comanda o comportamento da ferramenta GNU date bastante enlouquecedoramente inconsistente. Vincent Lefèvre deu estes exemplos:

jdebp % date +%Y-%m-%d -d '2003-02-01 - 1 month'
2003-01-01
jdebp % date +%Y-%m-%d -d '2003-02-01 - 31 days'
2003-01-01
jdebp % date +%Y-%m-%d -d '2003-02-01 - 31 days + 1 month'
2003-01-29
jdebp % date +%Y-%m-%d -d '2003-02-01 - 1 month + 1 month'
2003-02-01
jdebp % date +%Y-%m-%d -d '2003-09-01 1 day ago + 1 month'
2003-09-30
jdebp % date +%Y-%m-%d -d '2003-09-01 1 day ago'
2003-08-31
jdebp % date +%Y-%m-%d -d '2003-08-31 + 1 month'
2003-10-01
jdebp %

O que realmente está acontecendo internamente em date é que durante o cálculo ele está construindo datas inválidas intermediárias com valores negativos em locais, como 2003-03-(-30) , por exemplo. Então, renormaliza essas datas inválidas depois que tudo estiver pronto, usando uma função da biblioteca padrão da linguagem C.

O que é não fazer é renormalizar a cada passo , como um humano faz. Portanto, 2003-02-01 menos 31 dias para o programa date do GNU é uma data inválida, o negativo em 30 de fevereiro , e não uma data válida em janeiro como um ser humano pode calcular. Adicione um mês, e isso se torna uma data inválida em março, ainda a 30 negativa, que finalmente renormaliza para essa data em janeiro, porque é claro que o ajuste para transformar -30 em um número maior que zero retrocede todo o mês de fevereiro. As datas inválidas não-normalizadas nos outros exemplos são 2003-10-00 , 2003-09-00 e 2003-09-31 .

Aplicando isso ao seu exemplo:

  • 2017-12-31 + 1 day é 2017-12-32 , que renormaliza para 2018-01-01 na saída do programa.
  • 2018-01-01 - 1 month é 2018-00-01 , que renormaliza para 2017-12-01 na saída do programa.
  • 2017-12-31 + 1 day - 1 month é 2017-11-32 , que renormaliza para 2017-12-02 na saída do programa.

Como você pode ver quando você renormaliza a cada passo você não obtém o mesmo resultado que aplicar todas as mudanças de uma só vez, porque o GNU date aplica múltiplas mudanças de uma só vez < em> não renormaliza a cada passo .

Leitura adicional

por 09.02.2018 / 08:40
0

Parece-me que date primeiro volta um mês e depois adiciona o dia, nesta ordem.

Se você alterar a ordem das operações no pipeline, obterá o mesmo resultado que o outro.

$ echo 20171231 | xargs -i date -d "{} -1 month" | xargs -i date -d "{} +1 day"
Sat Dec  2 00:00:00 EET 2017

O problema é que voltar um mês a partir de 31 de dezembro é problemático. A mesma data no mês anterior seria 31 de novembro, mas novembro tem apenas 30 dias. Em certo sentido, 31 de novembro é o mesmo que 01 de dezembro, portanto, dar o último tem alguma lógica para isso.

É claro que outra opção seria ir de 31 de dezembro a 30 de novembro, mas isso também não é totalmente sem problemas. Deve Nov 30 - 1 month ser 30 de outubro ou 31 de outubro?

Pode ser necessário implementar a lógica necessária manualmente.

    
por 08.02.2018 / 22:04
0

A razão é que isso acontece:

$ a=20171231; b=$(date -d "$a  -1 month"); echo "<$b>"
<Fri Dec  1 00:00:00 PST 2017>

A data do comando vai para o início do mês em dezembro.
Quando você adiciona 1 dia, vai para o dia 2 .

Em vez disso, quando o dia é 1 de janeiro, volta um mês inteiro

$ a=20180101; b=$(date -d "$a -1 month"); echo "<$b>"
<Fri Dec  1 00:00:00 PST 2017>

Essa é uma característica interna da data.

date volta para o mês anterior com o mesmo número de dia dado:

$ a=20171110; b=$(date -d "$a -1 month"); echo "<$b>"
<Tue Oct 10 00:00:00 PST 2017>

Essa é a data indicada em novembro de volta a outubro. Mas se o dia é 31, fica em apuros. Por exemplo, a partir de 31 de outubro não há 31 de setembro, então ele volta a 1 de outubro:

$ a=20171031; b=$(date -d "$a -1 month"); echo "<$b>"
<Sun Oct  1 00:00:00 AST 2017>

Os turnos do mês são exatos apenas quando o dia é 01, e fevereiro é um mês particularmente estranho:

$ a=20170331; b=$(date -d "$a -1 month"); echo "<$b>"
<Fri Mar  3 00:00:00 AST 2017>

Porque não há 31 de fevereiro.

    
por 08.02.2018 / 22:04