Wie kann ich mit GNU-Tools eine Datumsdauer berechnen und formatieren, nicht ein Ergebnisdatum?

Wie kann ich mit GNU-Tools eine Datumsdauer berechnen und formatieren, nicht ein Ergebnisdatum?

Bei all den zahlreichen Artikeln, die ich bisher gefunden habe, schien es ausschließlich darum zu gehen, ein Ergebnisdatum zu erhalten, was zwar immer noch nützlich ist, in diesem Fall aber nicht das, was ich will.

Beispiellink:Unix & Linux SE - Datumsunterschiede schnell berechnen.

Im datediffRahmen der anderen Fragen und Antworten ist dies eher das, was ich in Bezug auf ein Ergebnis für die Dauer von Datum/Uhrzeit möchte, und es verwendet im Wesentlichen Unix-Zeitstempelmathematik mit den vorangehenden Konvertierungen, aber ich möchte eine Granularität bis auf die Sekunde, weshalb ich nicht durch 86400 dividiere.

dateMit der verfügbaren Dauer in Sekunden möchte ich sie nun mithilfe des GNU- Befehls folgendermaßen in etwa so formatieren :date -d "@69600" "+ %Y years %m months %e days %H:%M:%S"

Mir ist klar, dass alles im Wesentlichen eine Datums-/Zeitdauer aus der Unix-Epoche ist, aber jetzt habe ich das Problem, dass die Tages-, Monats- und Jahreszahlen nicht bei 0 beginnen, was den gewünschten Dauerwert nicht korrekt darstellen würde.

Ich könnte dieses Format kürzen und weitere exprBefehle anwenden, um im Wesentlichen 1 oder 1970 von jedem Wert abzuziehen, aber ich frage mich, ob es eine andere, einfachere und einfachere Möglichkeit gibt, mit der Datums-/Uhrzeitberechnung umzugehen, um ein Dauerergebnis zu erzielen, als mathematische und Formatierungsschritte miteinander zu verketten. Vielleicht gibt es in GNU eine andere Option, datedie ich nutzen könnte, oder ein anderes Tool, das 2 Datums-/Uhrzeitargumente akzeptiert und mir sofort das gewünschte Ergebnis liefert.

Es wäre ein Plus, wenn es in Homebrew für Macs verfügbar wäre :).

Link zur einfachen Datumsmathematik:Walker News - Datumsarithmetik in Linux-Shell-Skripten

Links zur zufälligen Datumsformatierung:

Antwort1

MitDatumsutils'Sdatediff(leider kein GNU), (früher ddiff, dateutils.ddiffunter 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

(Daten werden als UTC übernommen, fügen Sie etwas wie hinzu, --from-zone=Europe/Londondamit die Daten als Ortszeit in der entsprechenden Zeitzone übernommen werden. --from-zone=localtimeFunktioniert möglicherweise für die Standardzeitzone im System; --from-zone="${TZ#:}"würde funktionieren, solange $TZder Pfad einer IANA-Zeitzonendatei angegeben wird (wie TZ=:Europe/London, nicht TZ=GMT0BST,M3.5.0/1:00:00,M10.5.0/2:00:00die TZ-Spezifikation im POSIX-Stil)).

Mitast-offendate, also leider immer noch nicht mit GNU-Tools (wenn Sie es ksh93als Ihre Shell verwenden, ist es datemöglicherweise als integrierte Funktion verfügbar), können Sie es verwenden, date -Eum die Differenz zwischen zwei Daten in einem Format zu erhalten, das zwei Zahlen mit Einheiten ergibt:

$ 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

Beachten Sie, dass alle oben genanntenStundeist nicht eindeutig, da Tage an Orten mit Sommerzeit (23, 24 oder 25) eine unterschiedliche Stundenzahl haben und auch Monate und Jahre eine unterschiedliche Anzahl von Tagen aufweisen. Daher ist eine höhere Genauigkeit als die beiden oben genannten Einheiten möglicherweise nicht sehr sinnvoll.

Beispielsweise liegt zwischen dem 01.01.2015 00:00:00 und dem 01.01.2016 00:00:00 oder zwischen dem 01.01.2016 00:00:00 und dem 01.01.2017 00:00:00 genau ein Jahr, aber das ist nicht die gleiche Dauer (365*24 Stunden in einem Fall, 366*24 Stunden im anderen).

Es gibt genau einen Tag zwischen 2017-03-24 12:00:00 und 2017-03-25 12:00:00 oder zwischen 2017-03-25 12:00:00 und 2017-03-26 12:00:00, aber wenn es sich dabei um die lokale Zeit in europäischen Ländern handelt (die am 2017-03-26 auf Sommerzeit umgestellt haben), danneinmalbeträgt in einem Fall 24 Stunden und im anderen 23 Stunden.

Mit anderen Worten: Eine Dauer, die Jahre, Monate, Wochen oder Tage erwähnt, ist nur dann sinnvoll, wenn sie mit einer der Grenzen verknüpft ist, auf die sie angewendet werden soll (und der Zeitzone). Sie können also eine Anzahl von Sekunden nicht in eine solche Dauer umrechnen, ohne zu wissen, auf welche Zeit (ab oder bis) sie angewendet werden soll (es sei denn, Sie möchten ungefähre Definitionen von Tag (24 Stunden), Monat (30*24 Stunden) oder Jahr (365*24 Stunden) verwenden).

Bis zu einem gewissen Grad ist sogar eine Dauer in Sekunden mehrdeutig. Der Vereinfachung halber werden die Sekunden in der Unix-Epochenzeit als der 86400. Teil eines bestimmten Erdentages 1 definiert . Diese Sekunden werden immer länger, während die Erde sich dreht.

Also etwa so (mit 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"

Oder in 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}'

Würde Ihnen im Allgemeinen kein korrektes Ergebnis liefern, da das Zeitdelta auf das Jahr 1970 angewendet wird und nicht auf das tatsächliche Startdatum 2016.

Das obige Beispiel gibt mir (in der Zeitzone Europa/London) Folgendes:

1 years, 0 months, 1 days, 01:00:00

anstatt

1 years, 0 months, 0 days, 00:00:00

(das ist für Sie möglicherweise immer noch eine ausreichend gute Annäherung).


1 Technisch gesehen ist ein Tag zwar 86400 Unix-Sekunden lang, doch netzwerkverbundene Systeme synchronisieren ihre Uhr normalerweise mit Atomuhren, die SI-Sekunden verwenden. Wenn eine Atomuhr 12:00:00.00 anzeigt, zeigen diese Unix-Systeme auch 12:00:00.00 an. Die einzige Ausnahme ist die Einführung von Schaltsekunden, bei denen es entweder eine Unix-Sekunde gibt, die 2 Sekunden dauert, oder ein paar Sekunden, die etwas länger dauern, um diese zusätzliche Sekunde auf einen längeren Zeitraum zu verteilen.

Es ist daher möglich, die genaue Dauer (in Atomsekunden) zwischen zwei Unix-Zeitstempeln (die von mit der Atomuhr synchronisierten Systemen ausgegeben werden) zu ermitteln: Ermitteln Sie die Differenz der Unix-Epochenzeit zwischen den beiden Zeitstempeln und addieren Sie die Anzahl der dazwischen eingefügten Schaltsekunden.

datediffhat auch eine -f %rSum die Anzahl derrealSekunden zwischen zwei Daten:

$ 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

Der Unterschied liegt in den 9 Schaltsekunden, die zwischen 1990 und 2010 hinzugefügt wurden.

Diese Zahl vonrealSekunden helfen Ihnen nicht, die Anzahl der Tage zu berechnen, da Tage keine konstante Anzahl vonrealSekunden. Zwischen diesen beiden Daten liegen genau 20 Jahre und diese 9 Schaltsekunden stehen dem Erreichen dieses Wertes eher im Weg. Beachten Sie auch, dass ddiff's %rSnur funktioniert, wenn es nicht mit anderen Formatbezeichnern kombiniert wird. Außerdem sind zukünftige Schaltsekunden nicht lange im Voraus bekannt, und Informationen über aktuelle Schaltsekunden sind möglicherweise nicht verfügbar. Beispielsweise kennt mein System die nach dem 01.07.2012 nicht.

Antwort2

Okay, nehmen wir also an, Sie haben zwei date-kompatible Zeichenfolgen, die zwei Zeitpunkte definieren, deren Dauer Sie dazwischen berechnen möchten:

echo $(($(date +%s -d "3 days ago")-$(date +%s -d "4 weeks 2 hours 1 minutes 33 seconds ago"))) | sed 's/-//'

Aber nehmen wir weiter an, Sie möchten es lesbarer gestalten:

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."

Antwort3

Zeit ist eine komplizierte Sache und es ist wichtig, Ihre Erwartungen beim Berechnen im Zaum zu halten. Ich glaube nicht, dass es technisch möglich ist, Ihre Anforderungen im Allgemeinen sowohl genau als auch präzise zu erfüllen, da eine bestimmte Anzahl von Sekunden einer anderen Anzahl von Minuten entsprechen kann, wenn Sie Dinge wie Schaltsekunden berücksichtigen, die selbst nicht auf einer vollständig vorhersehbaren Basis auftreten.

Anders ausgedrückt: Wir sagen, ein Tag hat 24 Stunden, aber nichtjedenEin Tag hat genau 24 Stunden. Wenn Sie also wissen möchten, wie viele Tage plus Minuten plus Sekunden eine bestimmte Zeitspanne umfasst, müssen Sie diese Zeitspanne irgendwo in Echtzeit verankern, um zu wissen, ob es hierbei eine Schaltsekunde gab oder ob der 29. April überhaupt irgendwo in dieser Zeitspanne lag.

Noch exotischer: Nicht jeder Monat hat die gleiche Anzahl Tage.

Wenn das kein Problem ist, führen Sie für die Sekundenzählung einfach eine einfache Arithmetikoperation aus. Verwenden Sie datezur Umrechnung in Sekunden seit Epoche, dividieren Sie durch 86.400, um Tage zu erhalten, den Rest durch 3.600, um Stunden zu erhalten, den Rest, um Minuten zu erhalten und so weiter.

verwandte Informationen