Outil sous UNIX pour soustraire des dates

22

Existe-t-il un outil dans Solaris UNIX (donc aucun outil GNU disponible) pour soustraire les dates? Je sais que sous Linux, nous avons gawkqui peut soustraire une date d'une autre. Mais dans Solaris le maximum que nous avons est nawk(amélioré awk) qui ne peut pas effectuer de calculs de date. Je ne peux pas non plus utiliser perl.

Existe-t-il un moyen de faire des calculs de date comme 20100909 - 20001010?

MISE À JOUR: Est-il bccapable d'effectuer des calculs de dates?

jyz
la source
1
Voir aussi Calculer rapidement les différences de date pour savoir quand la date GNU est disponible.
Gilles 'SO- arrête d'être méchant'

Réponses:

10

Voici un script awk que je viens d'écrire, devrait fonctionner avec un awk POSIX. Vous devrez essayer la version Solaris; rappelez-vous qu'il existe également deux versions d'Awk sur Solaris, une dans / bin et une dans / usr / xpg4 / bin / awk (qui est nawk, je crois).

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

Passez une chaîne de date YYYYmmdd et elle sera convertie en nombre de secondes depuis l'époque (avec un peu de donner pour être sur les limites du jour). Ensuite, vous pourrez soustraire les deux.

today=`echo 20110210 | awk -f convdate.awk`
then=`echo 20001231 | awk -f convdate.awk`
sincethen=`expr $today - $then`
Arcege
la source
J'ai vérifié votre logique avec Oracle. Pour certaines dates, c'est ok, mais cela génère un nombre flottant. J'ai peur de devoir tronquer un nombre entier, n'est-ce pas?
jyz
La décimale est la fraction de seconde et n'est pas nécessairement nécessaire.
Arcege
L'époque expire 20380119. Pourquoi ne pas utiliser le jour julien de l'année? Dupe ... unix.stackexchange.com/questions/302266/…
jas-
13

Malheureusement, aucun des utilitaires de ligne de commande POSIX ne fournit d'arithmétique sur les dates. date -det date +%ssont le chemin à parcourir si vous les avez, mais ce sont des extensions GNU.

Il y a un hack maladroit avec touchce genre d'œuvres pour vérifier qu'une date est au moins n jours dans le passé:

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

(Notez que ce code peut être désactivé de un si DST a démarré ou s'est arrêté dans l'intervalle et que le script s'exécute avant 1 heure du matin.)

Plusieurs personnes ont fini par implémenter des bibliothèques de manipulation de dates dans Bourne ou shell POSIX. Il y a quelques exemples et liens dans la FAQ comp.unix.shell .

L'installation d'outils GNU peut être le moyen le moins pénible.

Gilles 'SO- arrête d'être méchant'
la source
11

J'essaierais d'utiliser la datecommande qui fait partie de POSIX donc elle est à peu près partout. MISE À JOUR: Malheureusement, il semble que -d ne fait pas partie de la date POSIX et n'est probablement pas là sur Solaris. Ainsi, cela ne répondra probablement pas à la question des PO.

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

Maintenant d1et d2sont des entiers qui correspondent aux secondes depuis l'époque unix. Ainsi, pour obtenir la différence entre les deux, nous soustrayons ( $((d1-d2))en bash) et convertissons à toutes les unités que nous voulons. Les jours sont les plus faciles:

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

La façon de faire la conversion sera probablement différente si vous n'avez pas bash. Le moyen le plus portable peut être d'utiliser expr( la page de manuel posix d'expr ).

Steven D
la source
ouais cela ne répond pas à ma question car c'est Solaris ... mais merci pour l'idéie et le post :)
jyz
8

Pour mémoire, dateutils est ma tentative de fournir un ensemble d'outils portables couvrant l'arithmétique des dattes. Votre exemple se résume à

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

Le -ispécifie le format d'entrée.

hroptatyr
la source
2
Ce paquet est génial, et il existe dans les bibliothèques de l'univers Ubuntu (au moins pour Trusty). Sur un autre système, je pouvais le compiler facilement à partir de zéro. Hautement recommandé. Merci beaucoup!
Robert Muil
Egalement conditionné en Fedora et en EPEL, pour l'écosystème RH.
mattdm
4

Perl est susceptible d'être installé, et il est assez facile d'extraire des modules de CPAN , de les installer dans votre répertoire personnel et de vous y référer dans votre programme. Dans ce cas, le module Date :: Calc a un Delta_Dayssous-programme qui vous aidera.

glenn jackman
la source
3

Date GNU par rapport à Solaris:

Je le redis:

Trop de Solaris SysAdmins sont fiers de ne pas avoir délibérément installé les packages officiels de Sun (maintenant Oracle) qui rendent un système Solaris "compatible GNU" lorsqu'ils configurent un nouvel hôte. Me bat pourquoi.

GNU Date est excellent et devrait être disponible par défaut sur tout hôte Solaris, à mon humble avis.

Sous Solaris 10

Installez le package SFWcoreu à partir du CD Solaris Companion. Après l'installation, vous trouverez la date GNU dans/opt/sfw/bin/date

Sous Solaris 11

Vous l'avez peut-être déjà, car je pense qu'il fait partie de l'installation standard. Il est cependant appelé gdateafin de le distinguer de la version Sun de la date.

Faites-le s'il n'est pas installé:

pkg install // solaris / file / gnu-coreutils
peterh
la source
Merci pour le conseil. Pouvez-vous me donner un exemple d'utilisation? Je peux donc demander à sysadmin de l'installer ...
jyz
Sous Solaris 11, il sera installé comme les deux /usr/bin/gdateet /usr/gnu/bin/datevous pouvez donc choisir de l'utiliser soit par nom, soit par paramètre $ PATH.
alanc
2

Si vous avez 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"

Vous avez marqué votre question "gawk" mais vous dites "pas d'outils GNU". Gawk a l'arithmétique des dates.

En pause jusqu'à nouvel ordre.
la source
Non. Quelqu'un a modifié mon post et étiqueté "gawk" ...
jyz
2

python:

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

1. Définissez la date1 et la date2 au %jformat jour de l'année (001..366)

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

2. Calculez la différence avec expr

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

3. Donc, la réponse est de 32 jours

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

... ou solution monoligne

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

ou

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

ou

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

Avec date BSD pour 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
la source
0

Vous pouvez utiliser la bibliothèque awk Velour pour renvoyer la différence en quelques secondes:

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

Ou jours:

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