Todas as outras perguntas na rede SE lidam com cenários em que a data é assumida como sendo now
( Q ) ou onde apenas uma data é especificada ( Q ).
O que eu quero fazer é fornecer uma data e hora e depois subtrair uma hora.
Aqui está o que eu tentei primeiro:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
Isso resulta em 2018-12-10 06:39:55
- Adicionou 7 horas. Subtraído em 20:05 minutos.
Depois de ler a página man
e , pensei em corrigi-lo com isso:info
date
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
Mas, mesmo resultado. De onde ele tira as 7 horas?
Eu tentei outras datas também porque pensei que talvez tivéssemos 7200 segundos bissextos naquele dia, quem sabe lol. Mas mesmos resultados.
Mais alguns exemplos:
$ date -d "2018-12-16T00:00:00 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-17_02:00:00
$ date -d "2019-01-19T05:00:00 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-19_08:55:00
Mas aqui isso se torna interessante. Se eu omitir o tempo de entrada, ele funciona bem:
$ date -d "2018-12-16 - 24 hours" +%Y-%m-%d_%H:%M:%S
2018-12-15_00:00:00
$ date -d "2019-01-19 - 2 hours - 5 minutes" +%Y-%m-%d_%H:%M:%S
2019-01-18_21:55:00
$ date --version
date (GNU coreutils) 8.30
o que estou perdendo?
Atualização: adicionei um Z
no final e isso mudou o comportamento:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
Ainda estou confuso. Não há muito sobre isso na página de informações do GNU sobre a data.
Suponho que esse é um problema de fuso horário, mas citando o Wiki do calendário na ISO 8601 :
Se nenhuma informação de relação UTC for fornecida com uma representação de hora, presume-se que a hora esteja na hora local.
Qual é o que eu quero. Minha hora local também está definida corretamente. Não sei ao certo por que o date iria mexer com o fuso horário, neste simples caso de eu fornecer um datetime e querer subtrair algo dele. Não deve subtrair as horas da cadeia de datas primeiro? Mesmo que ele a converta primeiro em uma data e depois faça a subtração, se eu deixar de fora quaisquer subtrações, obtenho exatamente o que quero:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
Então, se esse é realmente um problema de fuso horário, de onde vem essa loucura?
Respostas:
Esse último exemplo deve ter esclarecido as coisas para você: fusos horários .
Como a saída varia claramente de acordo com o fuso horário, eu suspeitaria de algum padrão não óbvio adotado para uma sequência de tempo sem um fuso horário especificado. Testando alguns valores, parece ser UTC-05: 00 , embora não tenha certeza do que seja.
É usado apenas ao executar aritmética de datas.
Parece que o problema aqui é que não
- 2 hours
é considerado aritmético, mas como um especificador de fuso horário :Portanto, não apenas não está sendo feita nenhuma aritmética, parece haver um ajuste de 1 hora no
horário de verão, levando a um tempo um tanto absurdo para nós.Isso também vale para adição:
Depurando um pouco mais, a análise parece ser:
2019-01-19T05:00:00 - 2
(-2
sendo o fuso horário) ehours
(= 1 hora), com uma adição implícita. Torna-se mais fácil ver se você usa minutos:Então, bem, a aritmética da data está sendo feita, mas não a que pedimos. ¯ \ (ツ) / ¯
fonte
TZ=UTC date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
vsTZ=UTC date -d "2019-01-19T05:00:00 - 2 hours" +%Y-%m-%d_%H:%M:%S
)date
, conforme o padrão ISO 8601, se nenhum fuso horário for fornecido, a hora local (fuso horário) deve ser assumida, o que, no caso de uma operação aritmética, não é. Problema muito estranho para mim.- 2 hours
é considerado o especificador de fuso horário aqui.--debug
opção de data ! Ótima explicação.Funciona corretamente quando você converte a data de entrada em ISO 8601 primeiro:
fonte
date
iria atrapalhar, pois sem subtrações fornecidas, o fuso horário fica intocado e tudo é o esperado também, sem precisar fornecer nenhum informações ou conversão de fuso horário.date -I
também emite o especificador de fuso horário (por exemplo2018-12-10T00:00:00+02:00
) que corrige o problema descrito na resposta de OlorinTLDR: Isso não é um bug. Você acabou de encontrar um dos comportamentos sutis, mas documentados, de
date
. Ao executar a aritmética da horadate
, use um formato independente do fuso horário (como hora do Unix) ou leia com muita atenção a documentação para saber como usar corretamente este comando.O GNU
date
usa as configurações do sistema (aTZ
variável de ambiente ou, se não estiver definido, o padrão do sistema) para determinar o fuso horário da data alimentada com a opção-d
/--date
e a data relatada pelo+format
argumento. A--date
opção também permite substituir o fuso horário por seu próprio argumento de opção, mas não substitui o fuso horário de+format
. Essa é a raiz da confusão, IMHO.Considerando que meu fuso horário é UTC-6, compare os seguintes comandos:
O primeiro usa meu fuso horário para ambos
-d
e+format
. O segundo usa o UTC para-d
mas meu fuso horário para+format
. O terceiro usa o UTC para ambos.Agora, compare as seguintes operações simples:
Mesmo que o horário do Unix esteja me dizendo a mesma coisa, o horário "Normal" difere por causa do meu próprio fuso horário.
Se eu quisesse fazer a mesma operação, mas usando exclusivamente meu fuso horário:
fonte
-08:00
), basta anexá-lo à data e hora ... nada mais para mexer. Exemplo:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
fornece local: 2019-03-02 18:05:36+format
argumento. Por exemplo, no meu sistema, as saídas mesmo comando:local: 2019-03-02 20:05:39
(se eu adicionar%:z
a+format
, torna-se óbvio que a informação está correta e a discrepância é devido aos fusos horários).-d
e para o+format
Unix, como eu disse na resposta, para evitar resultados inesperados.O GNU
date
suporta aritmética simples de data, embora os cálculos de época, como mostrado na resposta do @sudodus, às vezes sejam mais claros (e mais portáteis).O uso de +/- quando não há fuso horário especificado no carimbo de data / hora aciona uma tentativa de corresponder a um fuso horário a seguir, antes que qualquer outra coisa seja analisada.
Aqui está uma maneira de fazer isso, use "ago" em vez de "-":
ou
(Embora você não possa usar "Z" arbitrariamente, ele funciona na minha zona, mas isso o torna um carimbo de data / hora da zona UTC / GMT - use sua própria zona ou% z /% Z acrescentando
${TZ:-$(date +%z)}
o carimbo de data / hora.)A adição de termos de tempo extra desses formulários ajusta o tempo:
Muitos ajustes complexos, em qualquer ordem, podem ser usados (embora termos relativos e variáveis como "14 semanas depois da segunda-feira" estejam pedindo problemas ;-)
(Há outra pequena armadilha aqui também,
date
sempre fornecerá uma data válida, assimdate -d "2019-01-31 1 month"
como 2019-03-03, assim como "no próximo mês")Dada a grande variedade de formatos de data e hora suportados, a análise de fuso horário é necessariamente superficial: pode ser um sufixo único ou com várias letras, um deslocamento de hora ou hora: minuto, um nome "America / Denver" (ou até mesmo um nome de arquivo no caso da
TZ
variável).Seu
2018-12-10T00:00:00
versão não funciona porque "T" é apenas um delimitador, não um fuso horário. A adição de "Z" ao final faz com que esse trabalho (sujeito à correção da zona escolhida) também seja esperado.Veja: https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html e, em particular, a seção 7.7.
fonte
date -d "2018-12-10 00:00:00 now -5 hours
outoday
ou0 hour
em vez denow
, qualquer coisa que dizdate
que o token após o tempo não é um deslocamento de fuso horário.Essa solução é fácil de entender, mas um pouco mais complicada, por isso eu a mostro como um shellscript.
date
linha de comando finalShellscript:
fonte