Todas las otras preguntas en la red SE tratan con escenarios en los que se supone que la fecha es now
( Q ) o donde solo se especifica una fecha ( Q ).
Lo que quiero hacer es proporcionar una fecha y hora, y luego restar una hora de eso.
Esto es lo que probé primero:
date -d "2018-12-10 00:00:00 - 5 hours - 20 minutes - 5 seconds"
Esto da como resultado 2018-12-10 06:39:55
: agregó 7 horas. Luego restado 20:05 minutos.
Después de leer la página man
y info
de date
, pensé que lo había solucionado con esto:
date -d "2018-12-10T00:00:00 - 5 hours - 20 minutes - 5 seconds"
Pero, el mismo resultado. ¿De dónde obtiene las 7 horas?
Intenté otras fechas también porque pensé que tal vez teníamos 7200 segundos bisiestos ese día, quién sabe jajaja. Pero los mismos resultados.
Algunos ejemplos más:
$ 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
Pero aquí se vuelve interesante. Si omito el tiempo de entrada, funciona bien:
$ 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
¿Qué me estoy perdiendo?
Actualización: agregué un Z
al final, y cambió el comportamiento:
$ date -d "2019-01-19T05:00:00Z - 2 hours" +%Y-%m-%d_%H:%M:%S
2019-01-19_04:00:00
Aunque todavía estoy confundido. No hay mucho sobre esto en la página de información de GNU sobre la fecha.
Supongo que esto es un problema de zona horaria, pero citando The Calendar Wiki en ISO 8601 :
Si no se proporciona información de relación UTC con una representación de hora, se supone que la hora es en hora local.
Que es lo que quiero. Mi hora local también está configurada correctamente. No estoy seguro de por qué la fecha interferiría con la zona horaria en este caso simple de que yo proporcione una fecha y hora y desee restarle algo. ¿No debería restar primero las horas de la cadena de fecha? Incluso si primero lo convierte en una fecha y luego hace la resta, si omito cualquier resta obtengo exactamente lo que quiero:
$ date -d "2019-01-19T05:00:00" +%Y-%m-%d_%H:%M:%S
2019-01-19_05:00:00
Así SI esto realmente es un problema de zona horaria, ¿de dónde viene esa locura viene?
Respuestas:
Ese último ejemplo debería haber aclarado cosas para usted: zonas horarias .
Como la salida varía claramente según la zona horaria, sospecharía que se toma un valor predeterminado no obvio para una cadena de tiempo sin una zona horaria especificada. Al probar un par de valores, parece ser UTC-05: 00 , aunque no estoy seguro de qué es eso.
Solo se usa cuando se realiza la aritmética de fechas.
Al parecer, el problema aquí es que
- 2 hours
se no se toma como la aritmética, sino como un especificador de zona horaria :Por lo tanto, no solo no se está haciendo aritmética, parece que hay un ajuste de 1 hora en el
horario de verano, lo que nos lleva a un tiempo un poco absurdo.Esto también es válido para la adición:
Depuración un poco más, el análisis parece ser:
2019-01-19T05:00:00 - 2
(-2
siendo la zona horaria), yhours
(= 1 hora), con una adición implícita. Se vuelve más fácil ver si usas minutos en su lugar:Entonces, bueno, se está haciendo la aritmética de fechas, pero no la que pedimos. ¯ \ (ツ) / ¯
fuente
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
, según el estándar ISO 8601, si no se proporciona una zona horaria, se debe suponer la hora local (zona), que en el caso de una operación aritmética, no lo es. Sin embargo, es un problema muy extraño para mí.- 2 hours
se toma como el especificador de zona horaria.--debug
opción de fecha ! Gran explicaciónFunciona correctamente cuando convierte la fecha de entrada a ISO 8601 primero:
fuente
date
podría estropear esto, ya que sin ninguna resta suministrada, la zona horaria se deja intacta y todo es como se esperaba sin tener que suministrar ningún información de zona horaria o conversión.date -I
también genera el especificador de zona horaria (p2018-12-10T00:00:00+02:00
. Ej. ) Que soluciona el problema descrito en la respuesta deTLDR: Esto no es un error. Acabas de encontrar uno de los comportamientos sutiles pero documentados de
date
. Al realizar operaciones aritméticas con el tiempodate
, use un formato independiente de la zona horaria (como el tiempo Unix) o lea con mucha atención la documentación para saber cómo usar este comando correctamente.GNU
date
utiliza la configuración de su sistema (laTZ
variable de entorno o, si no está configurada, la predeterminada del sistema) para determinar la zona horaria de la fecha alimentada con la opción-d
/--date
y la fecha informada por el+format
argumento. La--date
opción también le permite anular la zona horaria para su propio argumento de opción, pero no anula la zona horaria de+format
. Esa es la raíz de la confusión, en mi humilde opinión.Teniendo en cuenta que mi zona horaria es UTC-6, compare los siguientes comandos:
El primero usa mi zona horaria para ambos
-d
y+format
. El segundo usa UTC para-d
pero mi zona horaria para+format
. El tercero usa UTC para ambos.Ahora, compare las siguientes operaciones simples:
Incluso si la hora de Unix me dice lo mismo, la hora "Normal" difiere debido a mi propia zona horaria.
Si quisiera hacer la misma operación pero usando exclusivamente mi zona horaria:
fuente
-08:00
), simplemente agregue eso para ingresar la fecha-hora ... nada más para jugar. Ejemplo:date -d '2019-02-28 14:05:36-08:00 +2 days 4 hours 3 seconds' +'local: %F %T'
da local: 02/03/2018 18:05:36+format
argumento. Por ejemplo, en mi sistema, las salidas mismo comando:local: 2019-03-02 20:05:39
(si añado%:z
que+format
, se hace evidente que la información es correcta y la discrepancia se debe a las zonas horarias).-d
y para+format
Unix, como dije en la respuesta, para evitar resultados inesperados.GNU
date
admite aritmética de fecha simple, aunque los cálculos de tiempo de época como se muestra en la respuesta de @sudodus a veces son más claros (y más portátiles).El uso de +/- cuando no hay una zona horaria especificada en la marca de tiempo desencadena un intento de hacer coincidir una zona horaria a continuación, antes de analizar cualquier otra cosa.
Aquí hay una forma de hacerlo, use "ago" en lugar de "-":
o
(Aunque no puede utilizar arbitrariamente "Z", funciona en mi zona, pero eso lo convierte en una marca de tiempo de zona UTC / GMT; use su propia zona o% z /% Z agregando
${TZ:-$(date +%z)}
en su lugar a la marca de tiempo).Agregar términos de tiempo extra de estos formularios ajusta el tiempo:
Se pueden usar muchos ajustes complejos, en cualquier orden (aunque los términos relativos y variables como "14 semanas, por lo tanto, el lunes pasado" piden problemas ;-)
(También hay otro pequeño beartrap aquí,
date
siempre dará una fecha válida, por lo quedate -d "2019-01-31 1 month"
da 2019-03-03, al igual que "el próximo mes")Dada la gran variedad de formatos de hora y fecha admitidos, el análisis de la zona horaria es necesariamente descuidado: puede ser un sufijo de una o varias letras, una hora u hora: desplazamiento de minutos, un nombre "América / Denver" (o incluso un nombre de archivo en el caso de la
TZ
variable).Su
2018-12-10T00:00:00
versión no funciona porque "T" es solo un delimitador, no una zona horaria, agregar "Z" al final hace que el trabajo (sujeto a la corrección de la zona elegida) también se espere.Ver: https://www.gnu.org/software/tar/manual/html_node/Date-input-formats.html y en particular la sección 7.7.
fuente
date -d "2018-12-10 00:00:00 now -5 hours
otoday
, o0 hour
en lugar denow
, cualquier cosa que se dicedate
que el testigo después de que el tiempo no es un desplazamiento de zona horaria.Esta solución es fácil de entender, pero un poco más complicada, así que la muestro como un shellscript.
date
línea de comando finalShellscript:
fuente