Strumento in UNIX per sottrarre date


22

Esiste uno strumento in Solaris UNIX (quindi nessuno strumento GNU disponibile) per sottrarre le date? So che in Linux possiamo gawksottrarre una data da un'altra. Ma in Solaris il massimo che abbiamo è nawk(migliorato awk) che non può eseguire calcoli della data. Inoltre non posso usare perl.

C'è un modo per fare calcoli della data come 20100909 - 20001010?

AGGIORNAMENTO: è in bcgrado di eseguire calcoli delle date?


1
Vedi anche Calcola rapidamente le differenze di data , per quando è disponibile la data GNU.
Gilles 'SO- smetti di essere malvagio' il

Risposte:


10

Ecco uno script awk che ho appena scritto, dovrebbe funzionare con un awk POSIX. Dovrai provare la versione di Solaris; ricorda che ci sono anche due versioni di Awk su Solaris, una in / bin e una in / usr / xpg4 / bin / awk (che è nawk, credo).

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);
}
{}

Passa una stringa di data YYYYmmdd e verrà convertita in numero di secondi dall'Epoca (con un po 'di valore per essere nei limiti del giorno). Quindi sarai in grado di sottrarre i due.

today=`echo 20110210 | awk -f convdate.awk`
then=`echo 20001231 | awk -f convdate.awk`
sincethen=`expr $today - $then`

Ho verificato la tua logica con Oracle. Per alcune date è ok, tuttavia genera un numero float. Temo di dover troncare a un numero intero, vero?
jyz,

Il decimale è la frazione di secondo e non è necessariamente necessario.
Arcege,

L'epoca scade il 20380119. Perché non usare il giorno giuliano dell'anno? Dupe ... unix.stackexchange.com/questions/302266/…
jas-

13

Sfortunatamente, nessuna delle utility della riga di comando POSIX fornisce aritmetica nelle date. date -de date +%ssono la strada da percorrere se li hai, ma sono estensioni GNU.

C'è un trucco goffo con touchquel tipo di lavori per verificare che una data sia almeno n giorni nel passato:

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

(Si noti che questo codice può essere disattivato da uno se l'ora legale viene avviata o arrestata nell'intervallo e lo script viene eseguito prima dell'1.)

Diverse persone hanno finito per implementare le librerie di manipolazione della data nella shell Bourne o POSIX. Ci sono alcuni esempi e collegamenti nelle FAQ di comp.unix.shell .

L'installazione di strumenti GNU può essere la via per il minimo dolore.


11

Vorrei provare a usare il datecomando che fa parte di POSIX, quindi è praticamente ovunque. AGGIORNAMENTO: Sfortunatamente, sembra che -d non faccia parte della data POSIX e probabilmente non sia presente su Solaris. Pertanto, questo probabilmente non risponderà alla domanda dei PO.

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

Ora d1e d2sono numeri interi che corrispondono ai secondi dall'epoca unix. Quindi, per ottenere la differenza tra i due, sottraggiamo ( $((d1-d2))in bash) e convertiamo le unità che vogliamo. I giorni sono i più facili:

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

Come fare la conversione sarà probabilmente diverso se non hai bash. Il modo più portatile può essere quello di usare expr( la pagina man posix di expr ).


sì, questo non risponde alla mia domanda perché è Solaris ... ma grazie per l'ideia e la pubblicazione :)
jyz

8

Per la cronaca, dateutils è il mio tentativo di fornire una serie di strumenti portatili che coprono l'aritmetica delle date. Il tuo esempio si riduce a

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

La -ispecifica il formato di input.


2
Questo pacchetto è fantastico ed esiste nelle librerie dell'universo Ubuntu (almeno per Trusty). Su un altro sistema, potrei compilarlo facilmente da zero. Altamente raccomandato. Grazie mille!
Robert Muil,

Compresso anche in Fedora e in EPEL, per l'ecosistema RH.
Mattdm,


3

Data scritta GNU su Solaris:

Lo dico di nuovo:

Troppi amministratori di sistema Solaris sono orgogliosi di non installare deliberatamente i pacchetti ufficiali di Sun (ora Oracle) che rendono un sistema Solaris "compatibile GNU" quando configurano un nuovo host. Mi batte perché.

La data GNU è eccellente e dovrebbe essere disponibile per impostazione predefinita su qualsiasi host Solaris, IMHO.

Su Solaris 10

Installare il pacchetto SFWcoreu dal CD di Solaris Companion. Dopo l'installazione troverai la data GNU in/opt/sfw/bin/date

Su Solaris 11

Potresti già averlo perché credo che sia parte dell'installazione standard. Viene comunque chiamato gdateper distinguerlo dalla versione Sun della data.

Fallo se non installato:

pkg install // solaris / file / gnu-coreutils

Grazie per il consiglio. Puoi darmi un esempio di come usarlo? Quindi posso chiedere a sysadmin di installarlo ...
jyz,

Su Solaris 11, verrà installato come entrambi /usr/bin/gdatee /usr/gnu/bin/datequindi è possibile scegliere di usarlo per nome o per impostazione di $ PATH.
alanc,

2

Se hai Python:

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"

Hai taggato la tua domanda "gawk" ma dici "no GNU tools". Gawk ha l'aritmetica della data.


Non l'ho fatto Qualcuno ha modificato il mio post e taggato "gawk" ...
jyz

2

pitone:

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

1

1. Definire il formato data1 e data2 nel %jgiorno dell'anno (001..366)

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

2. Calcola la differenza con expr

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

3. Quindi, la risposta è di 32 giorni

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

... o Soluzione da 1 linea

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

o

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

o

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

0

Con data BSD per 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

0

È possibile utilizzare la libreria awk Velour per restituire la differenza in secondi:

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

O giorni:

$ velour -n 'print t_secday(t_utc(2010, 9, 9) - t_utc(2000, 10, 10))'
3621
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.