Gestione date

Creazione di un timestamp

È utile l’utilizzo del timestamp, ovvero la formattazione della data in una modalità particolarmente sintetica e ordinata per cifre più significative, cioè YYYYMMDDHHMMSS

TIMESTAMP=`date '+%Y%m%d%H%M%S'`

Epoch della data attuale

Ovvero il numero di secondi trascorsi dalla mezzanotte del 1° gennaio 1970, può essere generato in diversi modi, a seconda della versione del comando date

date +%s

date -u '+%S+%M*60+%H*3600+(%j-1)*86400+(%Y-1970)*31536000+\
((%Y-1969)/4)*86400'|bc

Oppure in perl:

/usr/bin/perl -e 'printf "%d\n", time;'

E anche in millisecondi

/usr/bin/perl -e 'use Time::HiRes qw(time);my $t = time;printf "%d%03d\n",$t,($t-int($t))*1000;'

Calcolo dell’epoch di una data

Esempio di calcolo dell’epoch del “01/01/2012 12.41.12”:

HOUR=12
MIN=41
SEC=11
DAY=01
MONTH=01
YEAR=2012
set -A MONTHS 0 0 31 59 90 120 151 181 212 243 273 304 334 365
echo "b=0;if(${MONTH}>2) if (${YEAR}%4==0) b=1; \
${SEC}+${MIN}*60+${HOUR}*3600+(${MONTHS[${MONTH}]} + ${DAY} + b-1)*86400+\
(${YEAR}-1970)*31536000+((${YEAR}-1969)/4)*86400" | bc

Conversione dell’epoch in data

Esempio di calcolo della data corrispondente all’epoch 1325421671:

echo 1325421671 |\
awk '{
        e=$1;
        split("0,365,730,1096,1461", ydq,",");
        split("0,31,59,90,120,151,181,212,243,273,304,334,365",mml,",");
        tot_m=int(e/60);sec=e-tot_m*60;
        tot_h=int(tot_m/60);min=tot_m-tot_h*60;
        tot_d=int(tot_h/24);hours=tot_h-tot_d*24;
        tot_q=int(tot_d/1461);dqua=tot_d-tot_q*1461;
        base_y=1970 + tot_q * 4;
        for(i=0;i<4;i++){
                if (dqua<ydq[i+1])break;
        }
        year=base_y + i - 1;
        dyear=dqua - ydq[i] + 1;
        leap=(year % 4)?0:1;
        mmlp=0;
        for(i=1;i<=12;i++)
        {
                mmll=(i>=2)?mml[i+1]+leap:mml[i+1];
                if(mmll>=dyear){
                        month=i;
                        day=dyear-mmlp;
                        break;
                }
                mmlp=mmll;
        }
        printf "%02d/%02d/%04d %02d:%02d:%02d\n",day,month,year,hours,min,sec;
}'

Numeri di giorni dall’Inizio del Tempo Unix

DD=02
MM=05
YY=2012
set -A MONTHS 0 0 31 59 90 120 151 181 212 243 273 304 334 365
echo "b=0;
if(${MM}>2) if (${YY}%4==0) b=1;
(${MONTHS[${MM}]} + ${DD} + b-1)+(${YY}-1970)*365+((${YY}-1969)/4)" | bc

e inversamente, un valore calcolato con il comando precedente si trasforma di formato data con

echo 20000 |\
awk '{
        e=$1;
        split("0,365,730,1096,1461", ydq,",");
        split("0,31,59,90,120,151,181,212,243,273,304,334,365",mml,",");
        tot_d=e
        tot_q=int(tot_d/1461);dqua=tot_d-tot_q*1461;
        base_y=1970 + tot_q * 4;
        for(i=0;i<4;i++){
                if (dqua<ydq[i+1])break;
        }
        year=base_y + i - 1;
        dyear=dqua - ydq[i] + 1;
        leap=(year % 4)?0:1;
        mmlp=0;
        for(i=1;i<=12;i++)
        {
                mmll=(i>=2)?mml[i+1]+leap:mml[i+1];
                if(mmll>=dyear){
                        month=i;
                        day=dyear-mmlp;
                        break;
                }
                mmlp=mmll;
        }
        printf "%02d/%02d/%04d\n",day,month,year;
}'

04/10/2024

Calcolo della Pasqua

Questo script implementa l’algoritmo per il calcolo della Pasqua Cristiana secondo il calendario gregoriano. Le quantità 24 e 5 in grassetto nelle formule valgono per gli anni compresi tra il 1900 e il 2099.

echo 2012 | awk '{
	y=$1;
	a=y%19;
	b=y%4;
	c=y%7;
	d=(19*a + 24)%30;
	e=(2*b + 4*c + 6*d + 5)%7;
	if ((d + e) < 10){
		h=3;
		k=(d + e + 22);
	}
	else{
		h=4;
		k=(d + e - 9);
		if (k==26) k=25;
		if (k==25 && d==28 && e==6 && a>10) k=18;
	}
	printf "%02d/%02d/%04d\n",k,h,y;
}'

Calcolo del giorno precedente

daybefore() 
{
   DD=$( echo $1 | cut -c 1-2 )
   MM=$( echo $1 | cut -c 3-4 )
   YY=$( echo $1 | cut -c 5-8 )

   LEAP=0 
   BIS=$(echo "$YY % 4"| bc) 
   test $BIS -eq 0 && LEAP=1 
   set -A MML 31 31 28 31 30 31 30 31 31 30 31 30 31
   MML[2]=$(( LEAP + 28 ))

   ND=$(( DD - 1 ))
   NM=$MM
   NY=$YY
   test $ND -eq 0 && NM=$(( MM - 1 )) 
   test $ND -eq 0 && ND=${MML[NM]} 
   test $NM -eq 0 && NY=$((NY - 1 )) 
   test $NM -eq 0 && NM=12 
   printf "%02d%02d%04d\n" $ND $NM $NY 
}

La funzione daybefore calcola il giorno precedente alla data passata come parametro

daybefore 01032012

Data di ieri:

daybefore $(date +%d%m%Y)

Calcolo del giorno della settimana

Viene restituito 0 per Domenica, 1 per Lunedì ecc.

Per la data odierna:

date +%u


Per una data qualunque:

DATA='02/05/2012'
read DD MM YY < <( echo $DATA | sed 'sx/x xg' )
echo "(6 - $( cal $MM $YY | awk 'NR==3' |wc -w ) + ( $DD % 7 ) ) %7" | bc

Validazione di una data

Sfruttando il comando cal è possibile verificare se una data è valida.

$ myDATE=22/07/2015
$ echo $myDATE |sed 's/\// /g'| xargs cal >/dev/null 2>/dev/null
$ echo $?
0

Nel caso di data non valida restituisce un codice di ritorno diverso da zero.

$ myDATE=33/07/2015
$ echo $myDATE |sed 's/\// /g'| xargs cal >/dev/null 2>/dev/null
$ echo $?
123