Herramienta en UNIX para restar fechas


22

¿Hay alguna herramienta en Solaris UNIX (por lo que no hay una herramienta GNU disponible) para restar fechas? Sé que en Linux tenemos gawkque puede restar una fecha de otra. Pero en Solaris, el máximo que tenemos es nawk(mejorado awk) que no puede realizar cálculos de fechas. Además no puedo usar perl.

¿Hay alguna manera de hacer cálculos de fechas como 20100909 - 20001010?

ACTUALIZACIÓN: ¿ bcPuede realizar cálculos de fechas?


1
Vea también Calcular rápidamente las diferencias de fechas , para cuando la fecha GNU esté disponible.
Gilles 'SO- deja de ser malvado'

Respuestas:


10

Aquí hay un script awk que acabo de escribir, debería funcionar con un POSIX awk. Tendrá que probar la versión de Solaris; recuerde que también hay dos versiones de Awk en Solaris, una en / bin y otra en / usr / xpg4 / bin / awk (que creo que es 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);
}
{}

Pase una cadena de fecha AAAAMMdd y se convertirá a la cantidad de segundos desde la Época (con un poco de donación por estar en los límites del día). Entonces podrás restar los dos.

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

Verifiqué tu lógica con Oracle. Para algunas fechas está bien, sin embargo, porque genera un número flotante. Me temo que tengo que truncar a un número entero, ¿verdad?
jyz

El decimal es la fracción de segundo y no necesariamente se necesita.
Arcege

La época expira 20380119. ¿Por qué no usar el día juliano del año? Dupe ... unix.stackexchange.com/questions/302266/…
jas-

13

Desafortunadamente, ninguna de las utilidades de línea de comando POSIX proporciona aritmética en fechas. date -dy date +%sson el camino a seguir si los tiene, pero son extensiones GNU.

Hay un truco torpe con touchese tipo de trabajos para verificar que una fecha tenga al menos n días en el pasado:

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

(Tenga en cuenta que este código puede estar desactivado por uno si el horario de verano se inició o se detuvo en el intervalo y el script se ejecuta antes de la 1 a.m.)

Varias personas terminaron implementando bibliotecas de manipulación de fechas en Bourne o en el shell POSIX. Hay algunos ejemplos y enlaces en las preguntas frecuentes de comp.unix.shell .

Instalar herramientas GNU puede ser la forma de menos dolor.


11

Intentaría usar el datecomando que es parte de POSIX, por lo que está casi en todas partes. ACTUALIZACIÓN: Desafortunadamente, parece que -d no es parte de la fecha POSIX y probablemente no esté en Solaris. Por lo tanto, esto probablemente no responderá a la pregunta de los OP.

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

Ahora d1y d2son enteros que corresponden a segundos desde la época de Unix. Por lo tanto, para obtener la diferencia entre los dos, restamos ( $((d1-d2))en bash) y ocultamos las unidades que queramos. Los días son los más fáciles:

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

La forma de hacer la conversión probablemente será diferente si no tienes bash. La forma más portátil puede ser usar expr( página de manual posix de expr ).


Si esto no responde a mi pregunta porque es Solaris ... pero gracias por el IDEA y la publicación :)
JYZ

8

Para el registro, dateutils es mi intento de proporcionar un conjunto de herramientas portátiles que cubran la aritmética de fechas. Tu ejemplo se reduce a

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

El -iespecifica el formato de entrada.


2
Este paquete es increíble y existe en las bibliotecas del universo de Ubuntu (al menos para Trusty). En otro sistema, podría compilarlo fácilmente desde cero. Muy recomendable. ¡Muchas gracias!
Robert Muil

También empaquetado en Fedora y en EPEL, para el ecosistema RH.
mattdm


3

Fecha Wrt GNU en Solaris:

Digo esto otra vez:

Demasiados administradores de sistemas Solaris se enorgullecen de no instalar deliberadamente los paquetes oficiales de Sun (ahora Oracle) que hacen que un sistema Solaris sea "compatible con GNU" cuando configuran un nuevo host. Me gana por qué.

GNU Date es excelente y debería estar disponible de forma predeterminada en cualquier host Solaris, en mi humilde opinión.

En Solaris 10

Instale el paquete SFWcoreu desde el CD Solaris Companion. Después de la instalación, encontrará la fecha GNU en/opt/sfw/bin/date

En Solaris 11

Es posible que ya lo tenga, ya que creo que es parte de la instalación estándar. Sin embargo, se llama gdatepara distinguirlo de la versión de fecha de Sun.

Haga esto si no está instalado:

pkg install // solaris / file / gnu-coreutils

Gracias por el consejo. ¿Me puede dar un ejemplo de cómo usarlo? Entonces puedo pedirle a sysadmin que lo instale ...
jyz

En Solaris 11, que se instalará como tanto /usr/bin/gdatey /usr/gnu/bin/datepor lo que puede optar por utilizar ya sea por su nombre o por ajuste de $ PATH.
alanc

2

Si tienes 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"

Etiquetó su pregunta "gawk" pero dice "no hay herramientas GNU". Gawk tiene fecha aritmética.


No lo hice Alguien editó mi publicación y etiquetó "gawk" ...
jyz

2

pitón:

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

1

1. Defina fecha1 y fecha2 en formato de %jdía del año (001..366)

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

2. Calcule la diferencia con expr

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

3. Entonces, la respuesta es 32 días

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

... o solución de una sola línea

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 fecha BSD para 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

Puede utilizar la biblioteca awk Velour para devolver la diferencia en segundos:

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

O días:

$ velour -n 'print t_secday(t_utc(2010, 9, 9) - t_utc(2000, 10, 10))'
3621
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.