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?

jyz
fuente
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`
Arcege
fuente
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.

Gilles 'SO- deja de ser malvado'
fuente
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 ).

Steven D
fuente
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.

hroptatyr
fuente
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
4

Perl es probable que se instala, y es bastante fácil de agarrar módulos de CPAN , instalarlos en su directorio personal, y se refieren a ellos en su programa. En este caso, el módulo Date :: Calc tiene una Delta_Dayssubrutina que ayudará.

Glenn Jackman
fuente
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
Peter
fuente
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.

Pausado hasta nuevo aviso.
fuente
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
akira
fuente
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:~$ 
Sabrina
fuente
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
OlivierOR
fuente
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
Steven Penny
fuente