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, quando a formatação da data é incluída em um único comando de dados, obtém-se o resultado como 2 de dezembro.
No comando acima, parece que -1 mês está tendo precedência sobre +1 dia.
Alguém pode me ajudar a entender como isso está funcionando?
Não, não há ordem de precedência.
Ironicamente, isso acabou de aparecer na lista de discussão dos usuários do Debian este mês, onde foi apontado que para um ser humano lendo os supostos comandos de manipulação de data em linguagem natural legíveis por humanos, o comportamento da
date
ferramenta GNU parece irritantemente inconsistente. Vincent Lefèvre deu estes exemplos: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 lugares, como2003-03-(-30)
por exemplo. Então ele renormaliza essas datas inválidas depois de tudo feito, usando uma função da biblioteca padrão da linguagem C.O que não está fazendo é renormalizar a cada passo , como um humano faz. Então 2003-02-01 menos 31 dias para o programa GNU
date
é uma data inválida, o 30 de fevereiro negativo , e não uma data válida em janeiro como um humano pode calcular. Adicione um mês e isso se tornará uma data inválida em março, ainda o dia 30 negativo, que finalmente se renormaliza para essa data em janeiro porque, é claro, o ajuste para se transformar-30
em um número maior que zero pula para trás durante todo o mês de fevereiro. As datas inválidas não normalizadas nos outros exemplos são2003-10-00
,2003-09-00
e2003-09-31
.Aplicando isso ao seu exemplo:
2017-12-31 + 1 day
é2017-12-32
, que é renormalizado2018-01-01
na saída do programa.2018-01-01 - 1 month
é2018-00-01
, que é renormalizado2017-12-01
na saída do programa.2017-12-31 + 1 day - 1 month
é2017-11-32
, que é renormalizado2017-12-02
na saída do programa.Como você pode ver, ao renormalizar a cada etapa , você não obtém o mesmo resultado ao aplicar todas as alterações de uma só vez, porque o GNU
date
aplicando várias alterações de uma só vez não renormaliza a cada etapa .Leitura adicional
/bin/date
: inconsistências de análise de data . Debian Bug #729952.date
. Erro GNU nº 26101.A razão é que isso acontece:
A data de comando vai para o início do mês de dezembro.
Quando você adiciona 1 dia, ele vai para o dia
2
.Em vez disso, quando o dia é 1º de janeiro, ele volta um mês inteiro
Essa é uma característica interna da data.
date
volta para o mês anterior com o mesmo número do dia fornecido:Essa é a data determinada em novembro que remonta a outubro. Mas se o dia for 31, ele terá problemas. Por exemplo, a partir de 31 de outubro não há 31 de setembro, então remonta a 1º de outubro:
As mudanças de mês são exatas apenas quando o dia é 01, fevereiro é um mês particularmente estranho:
Porque não existe 31 de fevereiro.
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 do outro.
O fato é que voltar um mês a partir de 31 de dezembro é problemático. A mesma data do 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.
É claro que outra opção seria ir de 31 de dezembro a 30 de novembro, mas isso também não é totalmente isento de problemas. Deve
Nov 30 - 1 month
então ser 30 de outubro ou 31 de outubro?Pode ser necessário implementar a lógica necessária manualmente.