# Congruenza di Zeller

La congruenza di Zeller è un algoritmo ideato da Christian Zeller nel XIX secolo per calcolare il giorno della settimana per qualsiasi data del calendario giuliano o gregoriano, basato sulla conversione fra il giorno giuliano e la data del calendario.

## Formula

Per il calendario gregoriano, la congruenza di Zeller prende la forma seguente:
    $h=\left(q+\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor +K+\left\lfloor {\frac {K}{4}}\right\rfloor +\left\lfloor {\frac {J}{4}}\right\rfloor -2J\right){\bmod {7}},$
La formula per il calendario giuliano è:
    $h=\left(q+\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor +K+\left\lfloor {\frac {K}{4}}\right\rfloor +5-J\right){\bmod {7}},$
Dove:
* h è il giorno della settimana (dove 0 = sabato, 1 = domenica, 2 = lunedì, ..., 6 = venerdì);
* q è la cifra indicante il giorno del mese;
* m è il la cifra indicante il mese, contando però i mesi da 3 a 14, a partire da marzo e terminando con febbraio (3 = marzo, 4 = aprile, 5 = maggio, ..., 14 = febbraio)
* K l'anno del secolo (le ultime due cifre dell'anno, ovvero $\lfloor anno{\bmod {1}}00\rfloor$) considerando però l'anno iniziato a marzo (vedi sotto).
* J è il secolo a base zero (cioè $anno/100$). Ad esempio: i secoli in base zero per il 1995 e il 2000 sono rispettivamente 19 e 20;
* l'operatore parte intera (o floor) $\lfloor ...\rfloor$ (da non confondere con le parentesi quadre [ ] ) indica che solo la parte intera minore deve essere considerata;
* $a{\bmod {b}}$ si riferisce all'operazione modulo, e indica il resto dopo la divisione.
In questo algoritmo, gennaio e febbraio vengono conteggiati come tredicesimo e quattordicesimo mese dell'anno precedente. Ad esempio, per il 2 febbraio 2010, l'algoritmo conta la data come il secondo giorno del quattordicesimo mese del 2009 (14/02/2009 nel formato GG/MM/AAAA)
Per ottenere il giorno della settimana secondo il formato ISO (in cui d va da 1 = lunedì a 7 = domenica), bisogna adattare d tramite la formula seguente:
    $d=((h+5){\bmod {7}})+1$

## Analisi

Queste formule si basano sul fatto che il giorno della settimana aumenta progressivamente in base all'incremento di ciascuna sottoparte di quella data. Ogni termine all'interno della formula concorre, quindi, a calcolare la compensazione necessaria per ottenere il giorno della settimana corretto.
Per il calendario gregoriano i parametri di questa formula possono essere spiegati come segue:
* $q$ rappresenta la progressione del giorno della settimana in base al giorno del mese, in cui ogni giorno successivo incrementa di 1 la cifra indicante il giorno della settimana.
* $K$ rappresenta la progressione del giorno della settimana in base all'anno. Supponendo che ogni anno sia lungo 365 giorni, la stessa data in ogni anno successivo verrà compensata da un valore di $365{\bmod {7}}=1$ .
* Poiché in ogni anno bisestile ci sono 366 giorni, è necessario tenerne conto aggiungendo un altro giorno al valore di compensazione del giorno della settimana. Ciò si ottiene aggiungendo $\left\lfloor {\frac {K}{4}}\right\rfloor$ all'offset. Questo termine viene calcolato come risultato intero. Tutto il resto viene scartato.
* Usando una logica simile, la progressione del giorno della settimana per ogni secolo può essere calcolata osservando che ci sono 36.524 giorni in un secolo normale e 36.525 giorni in ogni secolo divisibile per 400. Il termine $\left\lfloor {\frac {J}{4}}\right\rfloor -2J$ calcola questo fattore considerando che
$36.525{\bmod {7}}=6$ e
$36.524{\bmod {7}}=5$.
* Il termine $\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor$ si adatta alla variazione dei giorni del mese:
** A partire da gennaio i giorni del mese sono {31, 28/29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}. Tenendo presente il problema costituito dalla variante (28 o 29) dei giorni di febbraio, la formula richiede di spostare gennaio e febbraio fino alla fine, affinché il conteggio dei mesi a 28 giorni non abbia conseguenze.
** La formula calcola i giorni della settimana. Quindi, prendendo il numero di giorni in un mese modulo 7 (sempre a partire da gennaio) la sequenza sarebbe {3, 0/1, 3, 2, 3, 2, 3, 3, 2, 3, 2, 3}.
** Ogni anno, ogni cinque mesi, ci sono due mesi di 31 giorni consecutivi (luglio-agosto e dicembre-gennaio). Quindi nell'arco di 10 mesi a partire da marzo si ripete due volte la stessa sequenza di cinque mesi {3, 2, 3, 2, 3}. La frazione 13/5 = 2,6 e la funzione floor hanno lo scopo di fissare il periodo di 5 mesi.
* La funzione complessiva, $\operatorname {mod} \,7$, normalizza il risultato in modo che risieda nell'intervallo da 0 a 6, che restituisce l'indice del giorno della settimana corretto per la data da analizzare.
La formula differisce per il calendario giuliano perché questo calendario non ha una regola separata per i secoli bisestili e si può quindi considerare un numero fisso di giorni per ogni secolo.
Poiché il calendario gregoriano è stato adottato in tempi diversi in diverse regioni del mondo, il luogo in cui un evento è accaduto contribuisce a determinare il giorno della settimana corretto per stabilire una data avvenuta durante il periodo di transizione. Tuttavia, tenere in considerazione questo ulteriore fattore è necessario solo fino al 1929, cioè l'ultimo anno in cui il calendario giuliano era ancora in uso in almeno un paese del mondo, e non è più necessario per date a partire dal 1930 in poi.
Le formule possono essere usate proletticamente, considerando però che l'"Anno 0" è in realtà l'anno 1 a.C. (vedi numerazione degli anni ). Il calendario giuliano è infatti prolettico fino al 1º marzo del 4 d.C. a causa della cattiva gestione di Roma (ma non dell'Egitto) nel periodo successivo alla messa in vigore del calendario il 1º gennaio del 45 a.C. (che non era un anno bisestile). Inoltre, l'operatore modulo potrebbe troncare gli interi nella direzione sbagliata (considerando cioè la parte intera superiore, o ceiling, invece che la parte intera inferiore, o floor). Per ovviare a ciò, si può aggiungere un multiplo sufficiente di 400 anni gregoriani o 700 anni giuliani.

## Esempi

Per il 1º gennaio 2000, la data va trattata come fosse il 13º mese del 1999, quindi i valori sarebbero:
    $q=1$
    $m=13$
    $K=99$
    $J=19$
Quindi la formula valuta come $(1+36+99+24+4-38){\bmod {7}}=126{\bmod {7}}=0={\text{Saturday}}$
(in cui il 36 costituisce la parte intera di $(13+1)\times 13/5=182/5$).
Tuttavia, per il 1 marzo 2000, la data va trattata come il terzo mese del 2000, quindi i valori diventano
    $q=1$
    $m=3$
    $K=0$
    $J=20$
quindi la formula valuta come $(1+10+0+0+5-40){\bmod {7}}=-24{\bmod {7}}=4={\text{Wednesday}}$ .

## Implementazioni nel software
### Modifica di base

Le formule si basano sulla definizione matematica di divisione modulo, il che significa che −2 mod 7 è uguale a 5 positivo. Sfortunatamente, la maggior parte dei linguaggi informatici implementano la funzione resto in modo troncato, $-2{\bmod {7}}$ restituendo come risultato −2. Pertanto la corretta implementazione della congruenza di Zeller su un computer richiede una leggera modifica delle formule per garantire sempre il numeratore positivo. Il modo più semplice per farlo è sostituire − 2J con + 5J e − J con + 6J .
La congruenza di Zeller per il calendario gregoriano diventa quindi:
    $h=\left(q+\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor +K+\left\lfloor {\frac {K}{4}}\right\rfloor +\left\lfloor {\frac {J}{4}}\right\rfloor +5J\right){\bmod {7}},$
Per il calendario gregoriano la congruenza di Zeller diventa:
    $h=\left(q+\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor +K+\left\lfloor {\frac {K}{4}}\right\rfloor +5+6J\right){\bmod {7}}$

### Semplificazione comune

Zeller usò l'aritmetica decimale e trovò conveniente usare J e K per rappresentare l'anno. Ma quando si utilizza un computer, è più semplice gestire l'anno Y e il mese m modificati, corrispondenti a Y - 1 e m + 12 nei mesi di gennaio e febbraio.
Per il calendario giuliano la congruenza di Zeller diventa pertanto:
    $h=\left(q+\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor +Y+\left\lfloor {\frac {Y}{4}}\right\rfloor -\left\lfloor {\frac {Y}{100}}\right\rfloor +\left\lfloor {\frac {Y}{400}}\right\rfloor \right){\bmod {7}},$
In questo modo non vi è alcuna possibilità di arrotondamento per difetto dovuto al singolo termine negativo perché $\left\lfloor Y/4\right\rfloor \geq \left\lfloor Y/100\right\rfloor$ .
Per il calendario giuliano la congruenza di Zeller diventa invece:
    $h=\left(q+\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor +Y+\left\lfloor {\frac {Y}{4}}\right\rfloor +5\right){\bmod {7}},$
La semplificazione illustrata qui sopra per calcolare la congruenza di Zeller nel calendario gregoriano è citata, in una forma semplificata che restituisce 0 per domenica, nell'Appendice B al (EN) RFC 3339, su datatracker.ietf.org, Internet Engineering Task Force.

### Altre varianti

Almeno altri tre algoritmi condividono la struttura complessiva della congruenza di Zeller nel suo tipo di "semplificazione comune", utilizzando anche un m ∈ [3, 14] ∩ Z e il costrutto "anno modificato".
* Michael Keith ha pubblicato un pezzo di codice C molto breve nel 1990 per le date gregoriane. La componente della durata del mese ( $\left\lfloor {\frac {13(m+1)}{5}}\right\rfloor$ ) è sostituito da $\left\lfloor {\frac {23m}{9}}\right\rfloor +4$ .
* JR Stockton fornisce una versione Sunday-is-0 con $\left\lfloor {\frac {13(m-2)}{5}}\right\rfloor +2$, definendolo una variazione di Zeller.
* Claus Tøndering descrive $\left\lfloor {\frac {31(m-2)}{12}}\right\rfloor$ come sostituzione di Sunday-is-0.
È possibile mostrare che entrambe le espressioni progrediscono in un modo diverso da uno rispetto al componente originale della durata del mese nell'intervallo richiesto di m, risultando in un valore iniziale pari a 0 per domenica.