
Todas las toneladas de artículos que he encontrado hasta ahora parecían centrarse en obtener una fecha resultante, lo cual sigue siendo útil, pero no es lo que quiero en este caso.
Enlace de ejemplo:Unix y Linux SE: calcule rápidamente las diferencias de fechas.
En datediff
esas otras preguntas y respuestas, esto es más de lo que quiero referirme a un resultado de duración de fecha/hora, y esencialmente usa matemáticas de marca de tiempo de Unix con esas conversiones anteriores, pero quiero que mi granularidad se reduzca al segundo, por eso no t dividir por 86400.
Con la duración de segundos disponible, ahora quiero formatearlo con algo así como usar el date
comando GNU de esta manera:date -d "@69600" "+ %Y years %m months %e days %H:%M:%S"
Me doy cuenta de que todo es esencialmente una duración de fecha/hora de la época de Unix, pero ahora tengo el problema con los números de día, mes y año que no comienzan desde 0, lo que no representaría correctamente el valor de duración que quiero.
Podría empezar a cortar este formato y aplicar más expr
comandos para esencialmente restar 1 o 1970 de cada valor, pero me pregunto si hay alguna otra forma más fácil y sencilla de lidiar con el cálculo de fecha/hora para lograr un resultado de duración además de encadenar matemáticas. y formateo los pasos juntos. Tal vez haya alguna otra opción en GNU date
que pueda aprovechar, u otra herramienta que acepte 2 argumentos de fecha/hora e inmediatamente me dé el resultado que estoy buscando.
Tenerlo disponible en Homebrew para Mac sería una ventaja :).
Enlace matemático de fecha simple:Walker News - Aritmética de fechas en scripts de Shell de Linux
Enlaces de formato de fecha aleatorio:
Respuesta1
Confechautils'sdatediff
(no lo siento GNU), (anteriormente ddiff
, dateutils.ddiff
en Debian):
$ dateutils.ddiff -f '%Y years, %m months, %d days, %H:%0M:%0S' \
'2012-01-23 15:23:01' '2017-06-01 09:24:00'
5 years, 4 months, 8 days, 18:00:59
(fechas tomadas como UTC, agregue algo como --from-zone=Europe/London
que las fechas se tomen como hora local en la zona horaria correspondiente. --from-zone=localtime
Puede funcionar para la zona horaria predeterminada en el sistema; --from-zone="${TZ#:}"
funcionaría siempre que $TZ
se especifique la ruta de un archivo de zona horaria de la IANA (como TZ=:Europe/London
, no TZ=GMT0BST,M3.5.0/1:00:00,M10.5.0/2:00:00
especificación TZ de estilo POSIX)).
Conabiertodate
, así que todavía no con las herramientas GNU, lo siento (si las usa ksh93
como shell, date
puede estar disponible como una función incorporada), puede usarlas date -E
para obtener la diferencia entre dos fechas en un formato que proporciona 2 números con unidades:
$ date -E 1970-01-01 2017-06-01
47Y04M
$ date -E 2017-01-01 2017-06-01
4M29d
$ date -E 12:12:01 23:01:43
10h49m
Tenga en cuenta que cualquier cosa por encimahoraes ambiguo, ya que los días tienen un número variable de horas en lugares con horario de verano (23, 24 o 25) y los meses y años tienen un número variable de días, por lo que puede que no tenga mucho sentido tener más precisión que las dos unidades anteriores.
Por ejemplo, hay exactamente un año entre 2015-01-01 00:00:00 y 2016-01-01 00:00:00 o entre 2016-01-01 00:00:00 y 2017-01-01 00: 00:00, pero no es la misma duración (365*24 horas en un caso, 366*24 horas en el otro)
Hay exactamente un día entre 2017-03-24 12:00:00 y 2017-03-25 12:00:00 o entre 2017-03-25 12:00:00 y 2017-03-26 12:00:00, pero cuando esa es la hora local en los países europeos (que cambiaron al horario de verano el 26 de marzo de 2017), esoun díaes de 24 horas en un caso y de 23 horas en el otro.
En otras palabras, una duración que menciona años, meses, semanas o días solo es significativa cuando se asocia a uno de los límites a los que debe aplicarse (y la zona horaria). Por lo tanto, no puede convertir una cantidad de segundos a dicha duración sin saber a qué hora (desde o hasta) debe aplicarse (a menos que desee utilizar definiciones aproximadas de día (24 horas), mes (30*24 horas) o año (365*24 horas)).
Hasta cierto punto, incluso una duración en segundos es ambigua. Para simplificar, los segundos en la época de Unix se definen como la parte 86400 de un día terrestre determinado 1 . Esos segundos son cada vez más largos a medida que la Tierra gira.
Entonces algo como (con GNU date
):
d1='2016-01-01 00:00:00' d2='2017-01-01 00:00:00'
eval "$(date -d "@$(($(date -d "$d2" +%s) - $(date -d "$d1" +%s)))" +'
delta="$((%-Y - 1970)) years, $((%-m - 1)) months, $((%-d - 1)) days, %T"')"
echo "$delta"
O en fish
:
date -d@(expr (date -d $d2 +%s) - (date -d $d1 +%s)) +'%Y %-m %-d %T' | \
awk '{printf "%s years, %s months, %s days, %s\n", $1-1970, $2-1, $3-1, $4, $5}'
Por lo general, no le daría algo correcto, ya que el delta de tiempo se aplica a 1970 en lugar de la fecha de inicio real de 2016.
Por ejemplo, arriba, eso me da (en una zona horaria de Europa/Londres):
1 years, 0 months, 1 days, 01:00:00
en lugar de
1 years, 0 months, 0 days, 00:00:00
(esa aún puede ser una aproximación suficientemente buena para usted).
1 Técnicamente, mientras que un día tiene una duración de 86400 segundos Unix, los sistemas conectados a la red normalmente sincronizan su reloj con relojes atómicos utilizando segundos SI. Cuando un reloj atómico dice 12:00:00.00, esos sistemas Unix también dicen 12:00:00.00. La excepción es solo con la introducción de segundos intercalares, donde hay un segundo Unix que dura 2 segundos o unos pocos segundos que duran un poco más para manchar ese segundo extra en un período más largo.
Por lo tanto, es posible conocer la duración exacta (en términos de segundos atómicos) entre dos marcas de tiempo Unix (emitidas por sistemas sincronizados con el reloj atómico): obtenga la diferencia de tiempo de época Unix entre las dos marcas de tiempo y agregue el número de saltos. segundos que se han añadido en el medio.
datediff
también tiene un -f %rS
para obtener el número derealsegundos entre dos fechas:
$ dateutils.ddiff -f %S '1990-01-01 00:00:00' '2010-01-01 00:00:00' 631152000 $ dateutils.ddiff -f %rS '1990-01-01 00:00:00' '2010-01-01 00:00:00' 631152009
La diferencia es por los 9 segundos intercalares que se agregaron entre 1990 y 2010.
Ahora bien, ese número derealLos segundos no te ayudarán a calcular el número de días, ya que los días no tienen un número constante derealsegundos. Hay exactamente 20 años entre esas 2 fechas y esos 9 segundos intercalares en lugar de obstaculizar el camino para llegar a ese valor. También tenga en cuenta que solo ddiff
funciona %rS
cuando no se combina con otros especificadores de formato. Además, los segundos intercalares futuros no se conocen con mucha antelación, pero también es posible que no esté disponible información sobre los segundos intercalares recientes. Por ejemplo, mi sistema no reconoce los posteriores al 01/07/2012.
Respuesta2
Bien, digamos que tienes dos date
cadenas compatibles que definen dos puntos en el tiempo entre los que deseas calcular la duración intermedia:
echo $(($(date +%s -d "3 days ago")-$(date +%s -d "4 weeks 2 hours 1 minutes 33 seconds ago"))) | sed 's/-//'
Pero digamos además que lo desea más legible:
convertsecs() {
hours=$(($1/3600))
minutes=$(($1%3600/60))
seconds=$(($1%60))
}
totalduration="$(($(date +%s -d "3 days ago")-$(date +%s -d "4 weeks 2 hours 1 minutes 33 seconds ago"))) | sed 's/-//'"
convertsecs "$totalduration"
echo "Duration was ${hours} hours, ${minutes} minutes, and ${seconds} seconds."
Respuesta3
El tiempo es algo complicado y es importante gestionar tus expectativas mientras lo calculas. No creo que sea técnicamente posible hacer lo que pides con exactitud y precisión en el caso general, ya que un número determinado de segundos puede corresponder a un número diferente de minutos una vez que consideras cosas como los segundos intercalares, que en sí mismos no ocurren. sobre una base totalmente predecible.
Dicho de otra manera, aunque decimos que un día tiene 24 horas, nocadael día es precisamente 24 horas, por lo que si desea saber cuántos días más minutos más segundos fue una duración determinada, debe anclar esa duración en algún lugar en tiempo real para saber si hubo o no un segundo intercalar allí, o incluso si el 29 de abril existió o no en algún momento de la duración.
Aún más exótico, no todos los meses tienen la misma cantidad de días.
Si eso no es una preocupación, simplemente cuente los segundos mediante aritmética básica; utilícelo date
para convertir a segundos desde época, divida por 86400 para obtener días, el resto por 3600 para obtener horas, el resto para obtener minutos, etc.