Un calendario perpetuo è un metodo che permette di ricavare il giorno della settimana (lunedì, martedì, mercoledì, giovedì, venerdì, sabato, domenica) di una qualsiasi data del calendario.

Sotto di algoritmo, uno dei più semplici è l'algoritmo creato da F. Berio nel 1924, consistente nel sommare 5 termini, facendo uso dell'operazione di modulo per ridurre il risultato della somma ad un valore inferiore a 7. Tale operazione (indicata dal simbolo "mod") è analoga all'aritmetica dell'orologio (secondo cui ad es. le ore 15 corrispondono alle ore 3 poiché 15 mod 12 = 3) e consiste nel resto della divisione (quindi 18 mod 7 = 4 poiché e il resto della divisione è 4; o, equivalentemente, poiché togliendo 7 due volte da 18, il resto vale 4).

L'algoritmo

Calendario gregoriano

Presa una data gg/mm/ssaa, le sue componenti son descritte nella seguente tabella:

Il numero corrisponde a con le limitazionigggiorno del mese da 1 a 31mmmese dell'annoda 1 a 12ssprime due cifre dell'anno [int(anno / 100)] da 15 in poiaaultime due cifre dell'anno (anno mod 100) da 0 a 99

L'algoritmo consiste nel determinare cinque addendi G, M, S, A, B e nel calcolare [(G + M + S + A + B) mod 7] ; l'operazione di modulo può essere eseguita non solo dopo aver sommato i cinque addendi ma anche, opzionalmente, su qualunque addendo o somma parziale.

Il giorno del mese (modulo 7) fornisce il primo addendo G dell'espressione finale: G = gg mod 7

Il secondo addendo M è un codice derivato dal mese, fornito dalla seguente tabella:

Mese M (anno non bisestile) M (anno bisestile)Gennaio6 5Febbraio2 1Marzo 2Aprile 5Maggio 0Giugno 3Luglio 5Agosto 1Settembre 4Ottobre 6Novembre 2Dicembre 4

Il terzo addendo S è un codice derivato dal secolo, cioè dalle prime due cifre ss dell'anno: ai 4 possibili risultati di "ss mod 4" si associa un numero S tale che: ss mod 40 1 2 3S0 5 3 1

e quindi, per i primi secoli nell'ambito di validità del calendario gregoriano, risulta: ss1516 17 18 1920212223S10 5 3 10531

In realtà, al secondo e terzo addendo potrebbero essere attribuite sette combinazioni differenti di valori: la combinazione di valori qui presentata per M ed S è quella ottimizzata per il secolo attuale poiché per ss = 20 si ha S = 0.

Il quarto addendo A si ricava dalle ultime due cifre aa dell'anno; poiché, nell'ambito di uno stesso secolo, i giorni della settimana si ripetono nel calendario gregoriano ogni 28 anni, si considera:

A = aa mod 28 Il quinto addendo B si ottiene a partire dalle ultime due cifre aa dell'anno, e rappresenta il numero di anni bisestili che sono sicuramente contenuti in aa anni (int indica la funzione parte intera del numero): B = int[(aa mod 28) / 4]

Ad esempio, per il 2023 il risultato dell'operazione è 5 poiché 23 contiene 5 blocchi interi di 4 anni ciascuno; aritmeticamente: B = int[(23 mod 28) / 4] = int(23 / 4) = 5

Determinati i cinque addendi, si calcola: [(G + M + S + A + B) mod 7] La formula fornisce un numero compreso tra 0 e 6 che indicherà il giorno della settimana:

Risultato Giorno0 Domenica1 Lunedì2 Martedì3 Mercoledì4 Giovedì5 Venerdì6 Sabato

I giorni antecedenti il venerdì 15 ottobre 1582, data dell'entrata in vigore del calendario gregoriano, non possono essere calcolati con le tabelle S mostrate sopra poiché era in vigore il calendario giuliano. L'algoritmo rimarrà valido fino all'eventuale futura introduzione di correzioni al calendario gregoriano.

Calendario giuliano

Per i giorni del calendario giuliano che vanno dall'anno 1 d.C. fino a giovedì 4 ottobre 1582, ultimo giorno in cui tale calendario è rimasto in vigore, si può usare un algoritmo simile al precedente per conoscere il giorno della settimana corrispondente.

Rimane valido il formato della data, gg/mm/ssaa, le cui componenti sono descritte da questa analoga tabella:

Il numero corrisponde a con le limitazionigggiorno del mese da 1 a 31mmmese dell'annoda 1 a 12ssprime due cifre dell'anno [int(anno / 100)] da 0 a 15aaultime due cifre dell'anno (anno mod 100) da 0 a 99

L'algoritmo consiste ancora nel determinare i cinque addendi G, M, S, A, B e nel calcolare [(G + M + S + A + B) mod 7].

Il giorno del mese (modulo 7) fornisce il primo addendo G dell'espressione finale: G = gg mod 7

Il secondo addendo M è il codice derivato dal mese, in questo caso fornito dalla seguente tabella:

Mese M (anno non bisestile) M (anno bisestile)Gennaio5 4Febbraio1 0Marzo 1Aprile 4Maggio 6Giugno 2Luglio 4Agosto 0Settembre 3Ottobre 5Novembre 1Dicembre 3

Il terzo addendo S è il codice derivato dal secolo, cioè dalle prime due cifre ss dell'anno. Per la determinazione di tale numero S si rileva la principale differenza rispetto al calendario gregoriano. Il suo valore si calcola a partire dalla formula:

S = 6 - (ss mod 7)

e quindi per i secoli del calendario giuliano in cui risulta valido tale algoritmo si ottiene:

ss00010203040506070809101112131415S6543210654321065

Il codice S associato al secolo è determinato in modo diverso perché nel calendario giuliano erano considerati bisestili anche gli anni multipli di 100 e non multipli di 400. Per tale ragione ogni secolo comprende 25 anni bisestili e questo fa sì che, da un secolo all'altro, la numerazione si sposti indietro di una unità.

Il quarto addendo A si ricava dalle ultime due cifre aa dell'anno, così come nel precedente algoritmo; si ottiene quindi:

A = aa mod 28

Anche il quinto addendo B si ottiene come nell'algoritmo precedente a partire dalle ultime due cifre aa dell'anno:

B = int[(aa mod 28) / 4]

Determinati i cinque addendi, si calcola: [(G + M + S + A + B) mod 7] La formula fornisce un numero compreso tra 0 e 6 che indicherà il giorno della settimana:

Risultato Giorno0 Domenica1 Lunedì2 Martedì3 Mercoledì4 Giovedì5 Venerdì6 Sabato

Esempi

Calendario giuliano

Data: 1º gennaio 1 d.C. (01/01/0001) G = 1 (gg = 01, 1 mod 7 = 1) M = 5 (gennaio) S = 6 (ss = 00, 6 - (0 mod 7) = 6 - 0 = 6) A = 1 (aa = 01, 1 mod 28 = 1) B = 0 (int[(1 mod 28) / 4] = int(1 / 4) = 0) G + M + S + A + B = 1 + 5 + 6 + 1 + 0 = 13 13 mod 7 = 6 Il giorno 1º gennaio 1 d.C. era un sabato

Data: 29 febbraio 700 (29/02/0700) G = 1 (gg = 29, 1 mod 7 = 1) M = 0 (febbraio, bisestile) S = 6 (ss = 07, 6 - (7 mod 7) = 6 - 0 = 6) A = 0 (aa = 00, 0 mod 28 = 0) B = 0 (int[(0 mod 28) / 4] = int(0 / 4) = 0) G + M + S + A + B = 1 + 0 + 6 + 0 + 0 = 7 7 mod 7 = 0 Il giorno 29 febbraio 700 era una domenica

Data: 1º luglio 1114 (01/07/1114) G = 1 (gg = 01, 1 mod 7 = 1) M = 4 (luglio) S = 2 (ss = 11, 6 - (11 mod 7) = 6 - 4 = 2) A = 14 (aa = 14, 14 mod 28 = 14) B = 3 (int[(14 mod 28) / 4] = int(14 / 4) = 3) G + M + S + A + B = 1 + 4 + 2 + 14 + 3 = 24 24 mod 7 = 3 Il giorno 1º luglio 1114 era un mercoledì

Data: 4 ottobre 1582 (04/10/1582) G = 4 (gg = 04, 4 mod 7 = 4) M = 5 (ottobre) S = 5 (ss = 15, 6 - (15 mod 7) = 6 - 1 = 5) A = 26 (aa = 82, 82 mod 28 = 26) B = 6 (int[(82 mod 28) / 4] = int(26 / 4) = 6) G + M + S + A + B = 4 + 5 + 5 + 26 + 6 = 46 46 mod 7 = 4 Il giorno 4 ottobre 1582 era un giovedì (ultimo giorno di validità del calendario giuliano)

Calendario gregoriano

Data: 15 ottobre 1582 (15/10/1582) G = 1 (gg = 15, 15 mod 7 = 1) M = 6 (ottobre) S = 1 (ss = 15, 15 mod 4 = 3) A = 26 (aa = 82, 82 mod 28 = 26) B = 6 (int[(82 mod 28) / 4] = int(26 / 4) = 6) G + M + S + A + B = 1 + 6 + 1 + 26 + 6 = 40 40 mod 7 = 5 Il giorno 15 ottobre 1582 era un venerdì (primo giorno di validità del calendario gregoriano)

Data: 25 febbraio 1800 (25/02/1800) G = 4 (gg = 25, 25 mod 7 = 4) M = 2 (febbraio) S = 3 (ss = 18, 18 mod 4 = 2) A = 0 (aa = 00, 0 mod 28 = 0) B = 0 (int[(0 mod 28) / 4] = int(0 / 4) = 0) G + M + S + A + B = 4 + 2 + 3 + 0 + 0 = 9 9 mod 7 = 2 Il giorno 25 febbraio 1800 era un martedì

Data: 22 ottobre 2008 (22/10/2008) G = 1 (gg = 22, 22 mod 7 = 1) M = 6 (ottobre) S = 0 (ss = 20, 20 mod 4 = 0) A = 8 (aa = 08, 8 mod 28 = 8) B = 2 (int[(8 mod 28) / 4] = int(8 / 4) = 2) G + M + S + A + B = 1 + 6 + 0 + 8 + 2 = 17 17 mod 7 = 3 Il giorno 22 ottobre 2008 era un mercoledì

Data: 15 aprile 2097 (15/04/2097) G = 1 (gg = 15, 15 mod 7 = 1) M = 5 (aprile) S = 0 (ss = 20, 20 mod 4 = 0) A = 13 (aa = 97, 97 mod 28 = 13) B = 3 (int[(97 mod 28) / 4] = int(13 / 4) = 3) G + M + S + A + B = 1 + 5 + 0 + 13 + 3 = 22 22 mod 7 = 1 Il giorno 15 aprile 2097 sarà un lunedì

Criteri per il calcolo mnemonico Per eseguire il calcolo mentalmente in modo efficiente, è opportuno in primo luogo memorizzare la tabella che fornisce l'addendo M in una forma autoreferente. Un metodo è memorizzare i nomi dei mesi troncati ad un numero di caratteri coincidente con il codice M (per non confondere i codici 5 e 6 è opportuno spezzare le sigle di 6 caratteri in due parti): MeseM (anno non bisestile)M (anno bisestile)GennaioGEN NAIGEN NAI -1FebbraioFEFE -1MarzoMAAprileAPRILMaggio.GiugnoGIULuglioLUGLIAgostoASettembreSETTOttobreOTT OBRNovembreNODicembreDICE In secondo luogo è opportuno tener conto che la somma S+A+B (il contributo dovuto all'anno) non varia per un anno intero; quindi, almeno per l'anno corrente, basta memorizzarla ad inizio anno.

In terzo luogo, è opportuno considerare che nell'ambito di un certo secolo (ss costante) il calendario si ripete ogni 28 anni (poiché 28 è minimo comune multiplo di 7 e 4, in cui 7 è la periodicità con cui si ripetono i giorni della settimana e 4 quella con cui si ripetono gli anni bisestili), quindi se l'anno è maggiore o uguale a 28 basta considerare come anno quello ottenuto sottraendo 28 o un suo multiplo (56 o 84).

Inoltre è da tener conto che, appena un addendo o una somma parziale risulta maggiore o uguale a 7, è opportuno sottrarre immediatamente 7 o suoi multipli in modo da minimizzare i valori in gioco. In particolare, il valore 7 risulta equivalente a 0.

Infine, è necessario conoscere la regola che nel calendario gregoriano stabilisce quali anni siano bisestili: se aa è diverso da 0, l'anno è bisestile se aa è divisibile per 4; se aa è uguale a 0 (anni secolari), l'anno è bisestile se ss è divisibile per 4.

Le operazioni da eseguire mentalmente (rapide nonostante l'apparente complessità) sono quindi: considerare il numero del giorno; se maggiore o uguale a 7, sottrarre subito il multiplo di 7 più alto possibile; sommare il codice del mese fornito in modo autoreferente dal nome del mese; se è gennaio o febbraio e l'anno è bisestile, va sottratto 1 (come da tabella del codice M); se la somma raggiunge o supera 7, sottrarre subito 7; sommare il codice del secolo: per il secolo attuale (ss = 20) il codice è 0 (come da tabella del codice S); per il secolo scorso (ss = 19) il codice è 1; se la somma raggiunge o supera 7, sottrarre subito 7; considerare l'anno: se è maggiore o uguale a 28 basta considerare come aa l'anno ottenuto sottraendo 28 o un suo multiplo (56 o 84); sommare l'anno aa, decurtato eventualmente di un multiplo di 7; sommare il numero di anni bisestili che sono sicuramente contenuti in aa: se aa non raggiunge 4 (è inferiore a 4) considerare 0 bisestili, altrimenti se non raggiunge 8 considerare 1 bisestile, altrimenti se non raggiunge 12 considerare 2 bisestili, ecc.; se la somma raggiunge o supera 7, sottrarre 7; il numero ottenuto indica il giorno della settimana: 1 = lunedì, 2 = martedì, ..., 6 = sabato, 0 (equivalente a 7) = domenica. Attraverso gli esempi viene illustrato come procedere operativamente per eseguire il calcolo.

Esempi di calcolo mnemonico Si illustrano in questa sezione esempi di calcolo dell'espressione (G + M + S + A + B) mod 7 in modo ottimizzato per essere eseguito mentalmente.

01/01/2003: pensando la data come 1 "GEN NAI" 2003, bisogna sommare 1 (il giorno) + 6 ("GEN NAI"); fin qui si ottiene 7: si sottrae subito 7 e resta 0; si prosegue sommando 0 (per il secolo attuale) + 3 (anno) + 0 (numero di bisestili in 3 anni) = 3, quindi mercoledì.