Tool in UNIX zum Subtrahieren von Datumsangaben

22

Gibt es ein Tool in Solaris UNIX (so dass kein GNU-Tool verfügbar ist), um Daten zu subtrahieren? Ich weiß, dass wir unter Linux gawkein Datum von einem anderen subtrahieren können. Aber in Solaris haben wir ein Maximum von nawk(verbessertawk ) dem keine Datumsberechnungen durchgeführt werden können. Ich kann auch kein Perl benutzen.

Gibt es eine Möglichkeit, Datumsberechnungen durchzuführen 20100909 - 20001010?

UPDATE: Kann ich Datumsberechnungen bcdurchführen?

jyz
quelle
1
Siehe auch Datumsunterschiede schnell berechnen , wenn GNU-Datum verfügbar ist.
Gilles 'SO - hör auf, böse zu sein'

Antworten:

10

Hier ist ein Awk-Skript, das ich gerade geschrieben habe und das mit einem POSIX-Awk funktionieren sollte. Sie müssen die Solaris-Version ausprobieren. Denken Sie daran, dass es unter Solaris auch zwei Versionen von Awk gibt, eine in / bin und eine in / usr / xpg4 / bin / awk (was meiner Meinung nach nawk ist).

BEGIN {
    daysofmonth["01"] = 0; daysofmonth["02"] = 31; daysofmonth["03"] = 59;
    daysofmonth["04"] = 90; daysofmonth["05"] = 120; daysofmonth["06"] = 151;
    daysofmonth["07"] = 181; daysofmonth["08"] = 212; daysofmonth["09"] = 243;
    daysofmonth["10"] = 273; daysofmonth["11"] = 304; daysofmonth["12"] = 334;
    fullday = 86400;
}
/[12][09][0-9][0-9][01][0-9][0123][0-9]/ {
    year = substr($0, 1, 4); month = substr($0, 5, 2); day = substr($0, 7, 2);
    date = ((year - 1970) * 365.25) + daysofmonth[month] + day - 1;
    if ((year % 4) == 0 && month > 2) { date = date + 1; }
    print date * fullday - (25200);
}
{}

Wenn Sie eine JJJJMMTT-Datumszeichenfolge durchgeben, wird sie in die Anzahl der Sekunden seit der Epoche konvertiert (mit ein wenig Nachgeben, damit die Tagesgrenzen eingehalten werden). Dann können Sie die beiden subtrahieren.

today=`echo 20110210 | awk -f convdate.awk`
then=`echo 20001231 | awk -f convdate.awk`
sincethen=`expr $today - $then`
Arcege
quelle
Ich habe Ihre Logik mit Oracle überprüft. Für einige Daten ist das ok, generiert aber dafür eine Gleitkommazahl. Ich fürchte, ich muss auf eine ganze Zahl kürzen, oder?
Jyz
Die Dezimalstelle ist der Bruchteil einer Sekunde und wird nicht unbedingt benötigt.
Arcege
Die Epoche läuft ab 20380119. Warum nicht den julianischen Tag des Jahres verwenden? Dupe ... unix.stackexchange.com/questions/302266/…
jas-18.02.18
13

Leider bietet keines der POSIX-Befehlszeilendienstprogramme eine Datumsberechnung an. date -dunddate +%s sind der richtige Weg, wenn Sie sie haben, aber sie sind GNU-Erweiterungen.

Es gibt einen ungeschickten Hack mit touchsolchen Arbeiten, um zu überprüfen, ob ein Datum mindestens n Tage in der Vergangenheit liegt:

touch -t 201009090000 stamp
if [ -n "$(find stamp -mtime +42)" ]; then ...

(Beachten Sie, dass dieser Code möglicherweise um eins deaktiviert ist, wenn die Sommerzeit in dem Intervall gestartet oder gestoppt wurde und das Skript vor 1 Uhr morgens ausgeführt wird.)

Mehrere Personen haben schließlich Datumsmanipulationsbibliotheken in der Bourne- oder POSIX-Shell implementiert. In den häufig gestellten Fragen zu comp.unix.shell finden Sie einige Beispiele und Links .

Das Installieren von GNU-Werkzeugen kann die schmerzärmste Methode sein.

Gilles 'SO - hör auf böse zu sein'
quelle
11

Ich würde versuchen, den dateBefehl zu verwenden, der Teil von POSIX ist, so ist es fast überall. UPDATE: Leider scheint -d nicht Teil des POSIX-Datums zu sein und wahrscheinlich auch nicht unter Solaris. Daher wird dies wahrscheinlich nicht die Frage des OP beantworten.

d1=`date -d 20100909 +%s`
d2=`date -d 20001010 +%s`

Now d1und d2sind ganze Zahlen, die Sekunden seit der Unix-Epoche entsprechen. Um den Unterschied zwischen den beiden zu erhalten, subtrahieren wir ( $((d1-d2))in Bash) und wandeln uns in die Einheiten, die wir wollen. Tage sind am einfachsten:

echo "$(((d1-d2)/86400)) days"

Die Konvertierung wird wahrscheinlich anders sein, wenn Sie keine Bash haben. Die portabelste Möglichkeit ist möglicherweise die Verwendung expr( expr's posix man page ).

Steven D
quelle
Ja, das beantwortet meine Frage nicht, weil es Solaris ist ... aber danke für die Idee und das Posten :)
jyz
8

Für das Protokoll ist dateutils mein Versuch, eine Reihe portabler Tools bereitzustellen , die Datumsarithmetik abdecken. Ihr Beispiel läuft auf

ddiff -i '%Y%m%d' 20001010 20100909
=>
  3621

Das -igibt das Eingabeformat an.

hroptatyr
quelle
2
Dieses Paket ist fantastisch und existiert in den Ubuntu-Universumsbibliotheken (zumindest für Trusty). Auf einem anderen System könnte ich es leicht von Grund auf neu kompilieren. Sehr empfehlenswert. Vielen Dank!
Robert Muil
Auch in Fedora und EPEL für das RH-Ökosystem verpackt.
Mattdm
4

Perl wird wahrscheinlich installiert und es ist einfach genug, Module aus dem CPAN zu holen , sie in Ihrem Home-Verzeichnis zu installieren und in Ihrem Programm darauf zu verweisen . In diesem Fall verfügt das Date :: Calc- Modul über eine Delta_DaysUnterroutine, die Abhilfe schafft.

Glenn Jackman
quelle
3

Wrt GNU-Datum unter Solaris:

Ich sage das noch einmal:

Zu viele Solaris-SysAdmins sind stolz darauf, die offiziellen Pakete von Sun (jetzt Oracle) nicht zu installieren, die ein Solaris-System "GNU-kompatibel" machen, wenn sie einen neuen Host konfigurieren. Schlägt mich warum.

GNU Date ist exzellent und sollte standardmäßig auf jedem Solaris-Host (IMHO) verfügbar sein.

Unter Solaris 10

Installieren Sie das Paket SFWcoreu von der Solaris Companion-CD. Nach der Installation finden Sie das GNU-Datum in/opt/sfw/bin/date

Unter Solaris 11

Möglicherweise haben Sie es bereits, da es meiner Meinung nach Teil der Standardinstallation ist. Es heißt jedochgdate , um es von der Sun-Version des Datums zu unterscheiden.

Tun Sie dies, wenn nicht installiert:

pkg install // solaris / file / gnu-coreutils
Peterh
quelle
Danke für den Tipp. Können Sie mir ein Beispiel geben, wie man es benutzt? Also kann ich
sysadmin
Unter Solaris 11 wird es als beides installiert, /usr/bin/gdateund /usr/gnu/bin/dateSie können wählen, ob Sie es nach Name oder nach $ PATH-Einstellung verwenden möchten.
Alanc
2

Wenn Sie Python haben:

from time import *
date1 = strptime("20100909","%Y%m%d")
date2 = strptime("20001010","%Y%m%d")
diff = mktime(date1) - mktime(date2)
print repr(d/86400) + " days"

Sie haben Ihre Frage mit "gawk" markiert, aber Sie sagen "no GNU tools". Gawk hat Datumsarithmetik.

Bis auf weiteres angehalten.
quelle
Habe ich nicht. Jemand hat meinen Beitrag bearbeitet und "gawk" getaggt ...
jyz
2

Python:

 from datetime import datetime as dt
 a = dt(2010, 9, 9)
 b = dt(2000, 10, 10)
 print (a - b).days
Akira
quelle
1

1. Definieren Sie Datum1 und %jDatum2 im Format Tag des Jahres (001..366)

user@linux:~$ date1=`date -d 20100909 +%j` 
user@linux:~$ date2=`date -d 20001010 +%j`

2. Berechnen Sie die Differenz mit expr

user@linux:~$ datediff=`expr $date2 - $date1`

3. Die Antwort lautet also 32 Tage

user@linux:~$ echo $datediff days
32 days
user@linux:~$ 

... oder Einzeilerlösung

user@linux:~$ echo $(( $(date -d 20001010 +%j) - $(date -d 20100909 +%j) )) days
32 days
user@linux:~$ 

oder

user@linux:~$ expr $(date -d 20001010 +%j) - $(date -d 20100909 +%j)
32
user@linux:~$

oder

user@linux:~$ expr `date -d 20001010 +%j` - `date -d 20100909 +%j`
32
user@linux:~$ 
Sabrina
quelle
0

Mit Datum BSD für macOS:

echo "Quelle est la date de début ?"
read DATE_DE_DEBUT
echo "Quelle est la date de fin ?"
read DATE_DE_FIN
ANNEE=$(($(echo $DATE_DE_FIN | awk -F "/" '{print $3}')-$(echo $DATE_DE_DEBUT  | awk -F "/" '{print $3}')))

echo " "

if [[ $ANNEE > 0 ]]; then

for((annee=$ANNEE-1 ; $ANNEE ; annee++))

  do
  #echo $annee  
  for((mois=0 ; 13 - $mois ; mois++))
      do
  #   echo année:$annee mois:$mois
          for((jour=0 ; 32 - $jour ; jour++))
              do
 #             echo année:$annee mois:$mois jour:$jour
           TEST=$(date -Rjf"%d/%m/%Y" -v +"$annee"y -v +"$mois"m -v +"$jour"d $DATE_DE_DEBUT +"%d/%m/%Y")
           if [[ $TEST = $DATE_DE_FIN ]]; then
                  echo "Différence entre le $DATE_DE_DEBUT et le $DATE_DE_FIN";
                  echo "est de :";
                  echo "$annee année(s) $mois mois $jour jour(s)";
             exit 0;
            fi


          done 
  done
  done

 else 
 annee=0
 for((mois=0 ; 13 - $mois ; mois++))
      do
#      echo année:$annee mois:$mois
          for((jour=0 ; 32 - $jour ; jour++))
              do
              #echo année:$annee mois:$mois jour:$jour
              TEST=$(date -Rjf"%d/%m/%Y" -v +"$annee"y -v +"$mois"m -v +"$jour"d $DATE_DE_DEBUT +"%d/%m/%Y")
              if [[ $TEST = $DATE_DE_FIN ]]; then 
                      echo "Différence entre le $DATE_DE_DEBUT et le $DATE_DE_FIN";
                     echo "est de :";
                     echo "$annee année(s) $mois mois $jour jour(s)";
              exit 0;
              fi
              done
      done

fi
OlivierOR
quelle
0

Mit der awk Velour-Bibliothek können Sie die Differenz in Sekunden zurückgeben:

$ velour -n 'print t_utc(2010, 9, 9) - t_utc(2000, 10, 10)'
312854400

Oder Tage:

$ velour -n 'print t_secday(t_utc(2010, 9, 9) - t_utc(2000, 10, 10))'
3621
Steven Penny
quelle