Narzędzie w systemie UNIX do odejmowania dat

22

Czy w systemie Solaris UNIX jest jakieś narzędzie (więc żadne narzędzie GNU nie jest dostępne) do odejmowania dat? Wiem, że w Linuksie mamy gawkmożliwość odjęcia jednej daty od drugiej. Ale w Solarisie mamy maksimum nawk(ulepszone awk), które nie może wykonać obliczeń daty. Nie mogę też używać perla.

Czy jest jakiś sposób na wykonanie obliczeń daty, takich jak 20100909 - 20001010?

AKTUALIZACJA: Czy jest w bcstanie wykonać obliczenia dat?

jyz
źródło
1
Zobacz także Szybkie obliczanie różnic dat , kiedy data GNU jest dostępna.
Gilles „SO- przestań być zły”

Odpowiedzi:

10

Oto skrypt awk, który właśnie napisałem, powinien współpracować z awk POSIX. Musisz wypróbować wersję Solaris; pamiętajcie, że istnieją również dwie wersje Awk na Solarisie, jedna w / bin i jedna w / usr / xpg4 / bin / awk (która, jak sądzę, jest nawk).

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

Przekaż ciąg daty YYYYmmdd, a zostanie on przekonwertowany na liczbę sekund od Epoki (z odrobiną dawania za to, że jest na granicy dnia). Następnie będziesz mógł odjąć dwa.

today=`echo 20110210 | awk -f convdate.awk`
then=`echo 20001231 | awk -f convdate.awk`
sincethen=`expr $today - $then`
Arcege
źródło
Sprawdziłem twoją logikę za pomocą Oracle. Dla niektórych dat jest ok, ale generuje liczbę zmiennoprzecinkową. Obawiam się, że muszę obciąć liczbę całkowitą, prawda?
jyz
Dziesiętny to ułamek sekundy i niekoniecznie jest potrzebny.
Arcege
Epoka wygasa 20380119. Dlaczego nie wykorzystać dnia roku w Julii? Dupe ... unix.stackexchange.com/questions/302266/…
jas-
13

Niestety, żadne z narzędzi wiersza poleceń POSIX nie zapewnia arytmetyki dat. date -di date +%ssą dobrą drogą, jeśli je masz, ale są to rozszerzenia GNU.

Istnieje niezręczny hack z touchtego rodzaju pracami, aby sprawdzić, czy data to co najmniej n dni w przeszłości:

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

(Pamiętaj, że ten kod może być wyłączony o jeden, jeśli DST uruchomi się lub zatrzyma w tym przedziale, a skrypt uruchomi się przed 1 rano).

Kilka osób zakończyło wdrażanie bibliotek manipulacji datami w powłoce Bourne lub POSIX. Istnieje kilka przykładów i linków w FAQ comp.unix.shell .

Instalowanie narzędzi GNU może być sposobem na najmniejszy ból.

Gilles „SO- przestań być zły”
źródło
11

Spróbowałbym użyć datepolecenia, które jest częścią POSIX, więc jest prawie wszędzie. AKTUALIZACJA: Niestety wydaje się, że -d nie jest częścią daty POSIX i prawdopodobnie nie ma jej w Solarisie. Zatem prawdopodobnie nie będzie to odpowiadało na pytanie PO.

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

Teraz d1i d2są liczbami całkowitymi, które odpowiadają sekund od początku epoki Uniksa. Tak więc, aby uzyskać różnicę między nimi, odejmujemy ( $((d1-d2))bash) i ukryjemy do dowolnych jednostek, które chcemy. Dni są najłatwiejsze:

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

Jak wykonać konwersję prawdopodobnie będzie inaczej, jeśli nie masz bash. Najbardziej przenośnym sposobem może być użycie expr( strona man posix expr ).

Steven D.
źródło
tak, to nie odpowiada na moje pytanie, ponieważ to Solaris ... ale dziękuję za ideę i wysłanie :)
jyz
8

Dla przypomnienia , dateutils to moja próba dostarczenia zestawu przenośnych narzędzi, które obejmują arytmetykę dat. Twój przykład sprowadza się do

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

-iOkreśla format wejściowy.

hroptatyr
źródło
2
Ten pakiet jest niesamowity i istnieje w bibliotekach wszechświata Ubuntu (przynajmniej dla Trusty). W innym systemie mogłem go łatwo skompilować od zera. Wysoce polecany. Dziękuję Ci bardzo!
Robert Muil
Pakowane również w Fedorze i EPEL, dla ekosystemu RH.
mattdm
4

Perl prawdopodobnie zostanie zainstalowany i łatwo jest pobrać moduły z CPAN , zainstalować je w katalogu domowym i odwołać się do nich w programie. W takim przypadku moduł Date :: Calc ma Delta_Dayspodprogram, który pomoże.

Glenn Jackman
źródło
3

Data publikacji GNU w systemie Solaris:

Mówię to jeszcze raz:

Zbyt wielu SysAdminów Solaris z dumą nie instaluje oficjalnych pakietów firmy Sun (obecnie Oracle), które sprawiają, że system Solaris jest „kompatybilny z GNU” podczas konfigurowania nowego hosta. Bije mnie dlaczego.

Data GNU jest doskonała i powinna być domyślnie dostępna na każdym hoście systemu Solaris, IMHO.

W systemie Solaris 10

Zainstaluj pakiet SFWcoreu z dysku CD Solaris Companion. Po instalacji znajdziesz datę GNU w/opt/sfw/bin/date

W systemie Solaris 11

Być może już go masz, ponieważ uważam, że jest to część standardowej instalacji. Jest on jednak wywoływany gdatew celu odróżnienia go od wersji daty Sun.

Zrób to, jeśli nie jest zainstalowany:

pkg install // solaris / file / gnu-coreutils
Peter
źródło
Dzięki za wskazówkę. Czy możesz podać mi przykład, jak go używać? Mogę więc poprosić sysadmin o zainstalowanie go ...
jyz
W systemie Solaris 11 zostanie zainstalowany jako jedno /usr/bin/gdatei drugie, /usr/gnu/bin/datewięc możesz użyć go według nazwy lub ustawienia $ PATH.
alanc
2

Jeśli masz 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"

Oznacziłeś swoje pytanie „gawk”, ale mówisz „bez narzędzi GNU”. Gawk ma arytmetykę daty.

Wstrzymano do odwołania.
źródło
Ja nie. Ktoś zredagował mój post i oznaczył „gawk” ...
jyz
2

pyton:

 from datetime import datetime as dt
 a = dt(2010, 9, 9)
 b = dt(2000, 10, 10)
 print (a - b).days
akira
źródło
1

1. Zdefiniuj datę 1 i %jdatę 2 w formacie dnia roku (001..366)

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

2. Oblicz różnicę za pomocą expr

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

3. Tak więc odpowiedź wynosi 32 dni

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

... lub rozwiązanie One-liner

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

lub

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

lub

user@linux:~$ expr `date -d 20001010 +%j` - `date -d 20100909 +%j`
32
user@linux:~$ 
Sabrina
źródło
0

Z datą BSD dla 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
źródło
0

Możesz użyć biblioteki awk Velor, aby zwrócić różnicę w kilka sekund:

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

Lub dni:

$ velour -n 'print t_secday(t_utc(2010, 9, 9) - t_utc(2000, 10, 10))'
3621
Steven Penny
źródło