Skillbook Logo
foto profilo

Skill Factory

Lista post > Impariamo Python creando il "Calendario Perpetuo" - Lezione 7

Impariamo Python creando il "Calendario Perpetuo" - Lezione 7

Gino Visciano | Skill Factory - 30/01/2020 23:29:56 | in Tutorials

In questa lezione creiamo un Calendario perpetuo,  per ricavare il giorno della settimana di qualsiasi data

L'algoritmo per creare un calendario perpetuo richiede le seguenti informazioni:

1) Codice dell'anno
2) Codice del mese
3) Numero del giorno della settimana
4) Se l'anno è Bisestile oppure no

Come calcolare il Codice dell'anno

Per calcolare Il codice dell'anno bisogna prima ottenere le due cifre a destra dell'anno scelto, ad esempio per l'anno 2019 serve il 19, che per comodità indichiamo con aa.

In Python per ottenere aa possiamo usare il comando seguente:

aa=int(str(anno)[2:])

La funzione str(...) converte la variabile intera anno  in stringa, mentre con [2:] indichiamo a Python di eliminare dalla stringa i due caratteri a sinistra. Infine i due caratteri che restano vengono di nuovo convertiti in intero ed assgnati alla variabile aa.

Successivamente dobbiamo calcolare il codice_anno_intermedio che è dato dalla formula:

codice_anno_intermedio=aa+int(aa/4)

Infine per ottenere il codice_anno occorre sottrarre al codice_anno_intermedio il suo multiplo di 7 più piccolo, come mostra la formula seguente:

codice_anno=codice_anno_intermedio-int(codice_anno_intermedio/7)*7.

Facciamo un esempio, calcoliamo il codice anno del 2019:

1) aa=19

2) codice_anno_intermendio=aa+int(aa/4)=19+4=23

3) codice_anno=codice_anno_intermedio-int(codice_anno_intermedio/7)*7=23-21=2

 

Come ottenere il Codice del mese

Il codice del mese è un valore intero difficile da calcolare, fortunatmente c'è già chi l'ha fatto per noi, quindi basta guardare semplicemente i risultati ottenuti: 

1)   gennaio = 6 se l'anno è bisestile 5
2)   febbraio =  2 se l'anno è bisestile 1
3)   marzo = 2
4)   aprile = 5
5)   maggio = 0
6)   giuugno = 3
7)   luglio = 5
8)   agosto = 1
9)   settembre = 4
10) ottobre = 6
11) novembre = 2
12) dicembre = 4

Come potete vedere per ottenere il codice del mese è importante sapere se l'anno di riferimento è bisestile.

Come verificare se un anno è bisestile

Nel calendario Gregoriano è bisestile un anno ogni 4. Questa correzione è necessaria perché astronomicamente un anno dura circa 365,25 giorni.
Un anno è bisestile nei casi seguenti:
 
1) se l'anno è divisibile contemporaneamente per 100 e per 400;
 
2) se l'anno è divisibile per 4
 
In Python per verificare se un anno è bisestile possiamo usare la funzione seguente:
 

def verificaBisestile(anno):
    bisestile=False
    if anno%100==0:
        if anno%400==0:
            bisestile=True
    elif anno%4==0:
            bisestile=True
    return bisestile

In questa funzione l'opertore % (modulo) permette di capire se l'anno è divisibile prima per 100 e poi per 400 oppure se è divisibile direttamente per 4.

Come calcolare il numero del giorno
Il numero del giorno corrisponde al giorno della settimana di una data qualunque del calendario, come mostra la tabella seguente:

1) Lunedì = 1
2) Martedì = 2
3) Meercoledì = 3
4) Giovedì = 4
5) Venerdì = 5
6) Sabato = 6
7) Domenica = 7 oppure 0

La formula per calcolare il numero del giorno è la seguente:

Numero giorno = (Codice anno + Codice Mese + Progressivo giorno del mese)%7

Facciamo un esempio, con un anno non bisestile ed uno bisestile:

Esempio 1

Il 18 marzo 2019, corrisponde ad un  lunedì, per verificare calcolare il numero del giorno:

1) aa=19

2) codice_anno_intermendio=aa+int(aa/4)=19+4=23

3) codice_anno=codice_anno_intermedio-int(codice_anno_intermedio/7)*7=23-21=2

4) codice_mese=2

5) Numero giorno = (Codice anno + Codice Mese + Progressivo giorno del mese)%7 = (2+2+18)%7=1

6) Il numero giorno 1 corrisponde a lunedì

Esempio 2

Il 10 gennaio 2020, corrisponde ad un venerdì, per verificare calcolare il numero del giorno:

1) aa=20

2) codice_anno_intermendio=aa+int(aa/4)=20+5=25

3) codice_anno=codice_anno_intermedio-int(codice_anno_intermedio/7)*7=25-21=4

4) codice_mese=5 perché l'anno 2020 è bisestile

5) Numero giorno = (Codice anno + Codice Mese + Progressivo giorno del mese)%7 = (4+5+10)%7=5

6) Il numero giorno 5 corrisponde a venerdi


In Python per ottenere il numero del giorno della settimana di una data qualunque del calendario, possiamo usare la funzione seguente:

def giornoSettimana(gg,mm,aaaa):
    aa=int(str(aaaa)[2:])
    codici_mesi=[6,2,2,5,0,3,5,1,4,6,2,4]
    if verificaBisestile(aaaa)==True:
       codici_mesi=[5,1,2,5,0,3,5,1,4,6,2,4]
    codice_anno_intermedio=(aa+int(aa/4))
    codice_anno=codice_anno_intermedio-int(codice_anno_intermedio/7)*7
    giorno=(codice_anno+codici_mesi[mm-1]+gg)%7
    return giorno

Analisi del codice Python

# Calendario perpetuo

import tkinter as tk # Classe che permette di creare GUI
from PIL import Image, ImageTk # Classi per gestire immagini
import time # Classe che permette di gestire il tempo
  
# Funzione che calcola il numero del giorno della settimana
def giornoSettimana(gg,mm,aaaa):
    aa=int(str(aaaa)[2:])
    codici_mesi=[6,2,2,5,0,3,5,1,4,6,2,4]
    if verificaBisestile(aaaa)==True:
       codici_mesi=[5,1,2,5,0,3,5,1,4,6,2,4]
    codice_anno_intermedio=(aa+int(aa/4))
    codice_anno=codice_anno_intermedio-int(codice_anno_intermedio/7)*7
    giorno=(codice_anno+codici_mesi[mm-1]+gg)%7
    return giorno  
  
# Funzione che stampa i mesi dell'anno scelto
def stampaGiorni(mm,aaaa):
    mesi=["Gennaio", "Febbraio", "Marzo", "Aprile","Maggio","Giugno","Luglio","Agosto","Settembre","Ottobre","Novembre","Dicembre"]
    giorni=[31, 28, 31, 30,31,30,31,31,30,31,30,31]
    if mm==2:
       if verificaBisestile(aaaa)==True:
          giorni[1]=29 # Imposta il mese di febbraio a 29 giorni se l'anno è bisestile
    conta=0
    titolo=mesi[mm-1]+" "+str(aaaa)
    centra="          "[:10-int(len(titolo)/2)]
    T2.insert(tk.END, '\n'+centra+titolo+'\n')
    T2.insert(tk.END, " Lu Ma Me Gi Ve Sa Do\n")
    gg_settimana=giornoSettimana(1,mm,aaaa)
    if gg_settimana==0:
       gg_settimana=7
    for i in range(1,gg_settimana):
        T2.insert(tk.END, "   ")
    conta=gg_settimana-1
    for gg in range(1,giorni[mm-1]+1):
        giorno="   "[:(3-len(str(gg)))]+str(gg)
        T2.insert(tk.END, giorno)
        conta=conta+1
        if conta==7:
           T2.insert(tk.END,'\n')
           conta=0
    T2.insert(tk.END,'\n')
    T2.insert(tk.END,"---------------------\n")
  
# Funzione che verifica se l'anno è bisestile
def verificaBisestile(aaaa):
    bisestile=False
    if aaaa%100==0:
        if aaaa%400==0:
            bisestile=True
    elif aaaa%4==0:
            bisestile=True
    return bisestile
  
# Funzione che imposta l'anno precedente e lo visualizza
def anno_precedente():
    global anno
    anno=anno-1
    label_anno.config(text=anno)
    main()
  
# Funzione che imposta l'anno successivo e lo visualizza
def anno_successivo():
    global anno
    anno=anno+1
    label_anno.config(text=anno)
    main()
  
# Funzione che crea i Frame in cui visualizzare i mesi dell'anno
def main():
    global T2
    F=[]
    offset=0 # Permette di stampare 3 mesi in ogni Frame
    for f in range(0,4):
        F.append(tk.Frame(Frame_body)) # Il Frame_body contiene 4 Frame ciascuno con 3 mesi 
        F[f].grid(column = f, row = 0)
    for f in range(0,4):
        T2=tk.Text(F[f], height=29, width=25,font=("Courier", 12)) # Imposta lo stile del testo per stampare i mesi dell'anno
        T2.pack(side=tk.LEFT, fill=tk.Y)
        for mm in range(1+offset,4+offset):
            stampaGiorni(mm,anno)
        offset=offset+3 # Inizio programma  
root = tk.Tk()
root.wm_title('CALENDARIO PERPETUO')
root.resizable(False, False)
icona = ImageTk.PhotoImage(Image.open("icona_cal.ico")) # Carica l'immagine dell'icona visualizzata in alto a sinistra della finestra del calendario
root.tk.call("wm", "iconphoto", root._w, icona)

# Frame in cui vengono visualizzati i pulsanti freccia e l'anno corrente
Frame_top=tk.Frame(root)
Frame_top.pack(side="top", fill="both", expand = True) # Associa il Frame_top alla finestra root e lo espande in tutto lo spazio disponibile
# Pulsante freccia a sinistra usato per visualizzare l'anno precedente
freccia_sx=tk.Button(Frame_top,text="<",  bd=1,command=anno_precedente, bg="blue",fg="white",font=("courier", 28))
freccia_sx.pack(side="left")
t = time.localtime()
anno=t.tm_year
label_anno = tk.Label(Frame_top, text=anno, bg="blue", fg="white",font=("Courier", 38))
label_anno.pack(side="left",fill="both",expand=True)
# Pulsante freccia a destra usato per visualizzare l'anno successivo
freccia_dx=tk.Button(Frame_top,text=">", bd=1, command=anno_successivo, bg="blue",fg="white",font=("courier", 28))
freccia_dx.pack(side="left")
# Frame in cui vengono visualizzati i 4 Frame ciascuno con tre mesi dell'anno
Frame_body=tk.Frame(root)
Frame_body.pack()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
# Frame in cui viene visualizzato il logo Skill Factory ed il messaggio "Powered by Skill Factory"

Frame_bottom=tk.Frame(root)
Frame_bottom.pack()
logo=ImageTk.PhotoImage(Image.open('logo_sf.png'))
label_logo=tk.Label(Frame_bottom, image=logo)
label_powered_sf=tk.Label(Frame_bottom, text="2020 - Powered by Skill Factory",font=("times", 14,'italic'))
label_logo.pack(side="left")
label_powered_sf.pack(side="left",fill="both",expand=True)
main()
tk.mainloop()

Conclusioni

Questa lezione è sicuramente molto interessante perché oltre a permettere di acquisire nuove conoscenze ed abilità sull'utilizzo del linguaggio Pythonpermette anche di conoscere le caratteristiche fondamentali del calendario Gregoriano, come ad esempio la durata effettiva di un anno astronomico ed il meccanismo dell'anno bisestile per correggere il ritardo che si accumula ogni quattro anni.

L'applicazione può essere compilata per ottenere un eseguibile che vi permetterà di usare il calendario perpetuo senza dover usare l'interprete Python.   

Per compilare lo script Python dovete installare il tool pyinstaller, con il comando:

pip install pyinstaller

Per compilare lo script dovete usare il comando:

pyinstaller calendario.py --noconsole

Dopo la compilazione travate tutto quello che vi serve nella cartella \dist\calendario.

Prima di lanciare il file eseguibile calendario.exe, dovete caricare nella cartella \dist\calendario tutte le immagini.

Arrivederci alla prossima lezione!

 


<< Lezione precedente



  Per scaricare le risorse di questa lezione clicca sul link seguente:risorse_lezione_07

 



 

Share Button
TOP