time - Tempo di Clock

Scopo: Funzioni per la manipolazione del tempo di clock

Il modulo time fornisce l'accesso a parecchi tipi di clock, utili per scopi diversi. Chiamate di sistema standard come time() ritornano il tempo "orologio" di sistema. L'orologio monotonico (monotonic()) può essere usato per misurare il tempo impiegato da un processo con un lungo tempo di esecuzione in quanto è garantito che non andrà mai indietro, anche se l'orario di sistema cambia. Per un test delle prestazioni perf_counter() fornisce accesso al clock con la risoluzione più alta disponibile per rendere più accurate le misurazioni di tempi brevi. Il tempo di CPU è disponibile tramite time(), e process_time() ritorna l'orario del processore e del sistema combinati.

Le implementazioni espongono le funzioni della libreria C per manipolare date e orari. Visto che sono legate all'implementazione C sottostante, alcuni dettagli (tipo l'inizio dell'epoca e il valore massimo di data supportato) sono specifici alla piattaforma. Fare riferimento alla documentazione della libreria per più completi dettagli.

Confrontare Clock

I dettagli di implementazione per i clock variano da piattaforma a piattaforma. Si usa get_clock_info() per avere accesso a informazioni di base circa l'implementazione corrente, compresa la risoluzione del clock.

# time_get_clock_info.py

import textwrap
import time


# Esempio modificato dal traduttore per gestire la traduzione dei
# clock disponibili
available_clocks = [
    ('clock', time.clock, 'orologio'),
    ('monotonic', time.monotonic, 'monotonico'),
    ('perf_counter', time.perf_counter, 'misuratore di prestazioni'),
    ('process_time', time.process_time, 'tempo di elaborazione'),
    ('time', time.time, 'tempo'),
]

for clock_name, func, translation in available_clocks:
    print(textwrap.dedent('''\
    {name}:
        modificabile   : {info.adjustable}
        implementazione: {info.implementation}
        monotonico     : {info.monotonic}
        risoluzione    : {info.resolution}
        attuale        : {current}
    ''').format(
        name=translation,
        info=time.get_clock_info(clock_name),
        current=func())
    )

Questo (e tutti gli esempi che seguono) è il risultato per un pc con processore x86_64 con sistema operativo Ubuntu, per un Mac OS X, ad esempio, gli orologi sono implementati con chiamate sottostanti diverse - n.d.t.

$ python3 time_get_clock_info.py
orologio:
    modificabile   : False
    implementazione: clock()
    monotonico     : True
    risoluzione    : 1e-06
    attuale        : 0.033279

monotonico:
    modificabile   : False
    implementazione: clock_gettime(CLOCK_MONOTONIC)
    monotonico     : True
    risoluzione    : 1e-09
    attuale        : 4616.771706342

misuratore di prestazioni:
    modificabile   : False
    implementazione: clock_gettime(CLOCK_MONOTONIC)
    monotonico     : True
    risoluzione    : 1e-09
    attuale        : 4616.771784419

tempo di elaborazione:
    modificabile   : False
    implementazione: clock_gettime(CLOCK_PROCESS_CPUTIME_ID)
    monotonico     : True
    risoluzione    : 1e-09
    attuale        : 0.033537894

tempo:
    modificabile   : True
    implementazione: clock_gettime(CLOCK_REALTIME)
    monotonico     : False
    risoluzione    : 1e-09
    attuale        : 1480843057.267927

Tempo "Orologio"

Una delle funzioni base del modulo time è time(), che restituisce il numero di secondi trascorsi dall'inizio dell'epoca sotto forma di valore a virgola mobile.

# time_time.py

import time

print("L'orario è:", time.time())

L'epoca è la partenza della misurazione del tempo, che per i sistemi Unix sono le ore 0:00 del primo gennaio 1970. Sebbene il valore sia sempre a virgola mobile, la precisione reale dipende dalla piattaforma.

$ python3 time_time.py

L'orario è: 1480843639.5855026

La rappresentazione a virgola mobile è utile quando si debbono conservare o confrontare date, ma non molto utile per produrre rappresentazioni leggibili dall'uomo. Per una registrazione o stampa del tempo ctime() può essere molto più utile.

# time_ctime.py

import time

print("L'ora è          :", time.ctime())
later = time.time() + 15
print('15 sec. da adesso:', time.ctime(later))

In questo caso la seconda chiamata di print() nell'esempio mostra come usare ctime() per formattare un valore di tempo diverso da quello corrente.

$ python3 time_ctime.py

L'ora è          : Sun Dec  4 10:31:53 2016
15 sec. da adesso: Sun Dec  4 10:32:08 2016

Clock Monotonici

Visto che time() si rivolge all'orologio di sistema e quest'ultimo può essere modificato dall'utente o da servizi di sistema per la sincronizzazione di orologi su molteplici computer, chiamando time() ripetutamente si potrebbero ottenere valori che vanno avanti e indietro. Il che potrebbe produrre un comportamento inatteso qualora si vogliano misurare durate oppure utilizzare questi tempi per calcoli. Per evitare queste situazioni si usa monotonic(), che ritorna sempre valori che vanno in avanti.

# time_monotonic.py

import time

start = time.monotonic()
time.sleep(0.1)
end = time.monotonic()
print('inizio    : {:>9.2f}'.format(start))
print('fine      : {:>9.2f}'.format(end))
print('intervallo: {:>9.2f}'.format(end - start))

Il punto di partenza del clock monotonico non è definito, quindi i valori restituiti sono utili solo per fare calcoli con altri valori di clock. In questo esempio la durata dell'attesa (time.sleep(0.1)) è misurata utilizzando monotonic().

$ python3 time_monotonic.py

inizio    :   5905.87
fine      :   5905.97
intervallo:      0.10

Tempo di Clock del Processore

Laddove time() restituisce un orario come fosse un normale orologio, clock() ritorna il tempo di clock del processore. I valori ritornati da clock() riflettono il tempo effettivo impiegato dal programma mentre è in esecuzione.

# time_clock.py

import hashlib
import time

# Dati da usare per calcolare somme di controllo md5
data = open(__file__, 'rb').read()

for i in range(5):
    h = hashlib.sha1()
    print(time.ctime(), ': {:0.3f} {:0.3f}'.format(time.time(), time.clock()))
    for i in range(100000):
        h.update(data)
    cksum = h.digest()

In questo esempio il tempo formattato ctime() viene stampato assieme ai valori a virgola mobile da time(), e clock() per ogni iterazione attraverso il ciclo.

Se si vuole eseguire l'esempio nel proprio sistema, si potrebbe dover aggiungere più cicli a quello più interno o lavorare con un numero maggiore di dati per vedere realmente la differenza.
$ python3 time_clock.py

Sun Dec  4 16:17:43 2016 : 1480864663.813 0.031
Sun Dec  4 16:17:43 2016 : 1480864663.928 0.145
Sun Dec  4 16:17:44 2016 : 1480864664.012 0.229
Sun Dec  4 16:17:44 2016 : 1480864664.089 0.306
Sun Dec  4 16:17:44 2016 : 1480864664.167 0.384

Tipicamente, il clock del processore non scorre se un programma non sta facendo nulla.

# time_clock_sleep.py

import time

template = '{} - {:0.2f} - {:0.2f}'

print(template.format(
    time.ctime(), time.time(), time.clock())
)

for i in range(3, 0, -1):
    print('Inattivo', i)
    time.sleep(i)
    print(template.format(
        time.ctime(), time.time(), time.clock())
    )

In questo esempio, il ciclo fa un lavoro minimo, mettendosi in pausa temporanea dopo ogni iterazione. Il valore di time() aumenta anche quando l'applicazione è in pausa temporanea, ma il valore di clock() rimane invariato.

$ python3 -u time_clock_sleep.py
Sun Dec  4 16:21:12 2016 - 1480864872.58 - 0.02
Inattivo 3
Sun Dec  4 16:21:15 2016 - 1480864875.58 - 0.02
Inattivo 2
Sun Dec  4 16:21:17 2016 - 1480864877.58 - 0.02
Inattivo 1
Sun Dec  4 16:21:18 2016 - 1480864878.58 - 0.02

La chiamata di sleep() ottiene il controllo dal thread corrente e gli chiede di attendere fino a che il sistema non esca dalla pausa. Se un programma ha un solo thread, l'applicazione viene effettivamente bloccata e non esegue alcuna attività.

Misuratore di Prestazioni

E' importante avere un orologio monotonico ad alta definizione per la misurazione delle prestazioni. Il determinare la migliore sorgente dati per l'orologio richiede conoscenza specifica della piattaforma, che Python fornisce con perf_counter().

# time_perf_counter.py

import hashlib
import time

# Dati da usare per calcolare somme di controllo md5
data = open(__file__, 'rb').read()

loop_start = time.perf_counter()

for i in range(5):
    iter_start = time.perf_counter()
    h = hashlib.sha1()
    for i in range(300000):
        h.update(data)
    cksum = h.digest()
    now = time.perf_counter()
    loop_elapsed = now - loop_start
    iter_elapsed = now - iter_start
    print(time.ctime(), ': {:0.3f} {:0.3f}'.format(
        iter_elapsed, loop_elapsed))

Così come per monotonic(), l'epoca per perf_counter() è indefinita, e i valori sono destinati all'uso per confrontare e calcolare valori, non tempi assoluti.

$ python3  time_perf_counter.py

Sun Dec  4 16:32:09 2016 : 0.355 0.355
Sun Dec  4 16:32:09 2016 : 0.309 0.664
Sun Dec  4 16:32:10 2016 : 0.307 0.971
Sun Dec  4 16:32:10 2016 : 0.311 1.282
Sun Dec  4 16:32:10 2016 : 0.310 1.592

Componenti di Time

Conservare il tempo come secondi trascorsi può essere utile in alcune situazioni, ma ci sono volte nelle quali si deve avere accesso ai singoli campi di una data (anno, mese, ecc.). Il modulo time definisce struct_time per mantenere i valori di data e ora con i componenti separati in modo da essere facilmente accessibili. Ci sono parecchie funzioni che lavorano con i valori di struct_time invece che con i valori a virgola mobile.

# time_struct.py

import time


def show_struct(s):
    print('  tm_year :', s.tm_year)
    print('  tm_mon  :', s.tm_mon)
    print('  tm_mday :', s.tm_mday)
    print('  tm_hour :', s.tm_hour)
    print('  tm_min  :', s.tm_min)
    print('  tm_sec  :', s.tm_sec)
    print('  tm_wday :', s.tm_wday)
    print('  tm_yday :', s.tm_yday)
    print('  tm_isdst:', s.tm_isdst)

print('gmtime:')
show_struct(time.gmtime())
print('\nlocaltime:')
show_struct(time.localtime())
print('\nmktime:', time.mktime(time.localtime()))

La funzione gmtime() ritorna l'orario corrente UTC. localtime() ritorna l'orario corrente in base al fuso orario applicato. mktime() ottiene una struct_time e la converte nella sua rappresentazione a virgola mobile.

$ python3  time_struct.py
gmtime:
  tm_year : 2016
  tm_mon  : 12
  tm_mday : 4
  tm_hour : 15
  tm_min  : 37
  tm_sec  : 30
  tm_wday : 6
  tm_yday : 339
  tm_isdst: 0

localtime:
  tm_year : 2016
  tm_mon  : 12
  tm_mday : 4
  tm_hour : 16
  tm_min  : 37
  tm_sec  : 30
  tm_wday : 6
  tm_yday : 339
  tm_isdst: 0

mktime: 1480865850.0

Lavorare con i Fusi Orari

Le funzioni per determinare il tempo corrente dipendono dall'avere impostato il fuso orario, sia da un programma che usando l'impostazione predefinita del fuso orario del sistema. La modifica del fuso orario non modifica l'orario effettivo, ma solo il modo in cui viene rappresentato.

Per modificare il fuso orario, si imposta la variabile di ambiente TZ, quindi si chiama tzset(). Si può specificare il fuso orario dettagliatamente, fino all'inizio e alla fine dell'ora legale; è in genere più semplice usare il nome del fuso orario e lasciare che le librerie sottostanti ricavino le altre informazioni.

In questo esempio il programma modifica il fuso orario con alcuni diversi valori e mostra come le modifiche si ripercuotono sulle altre impostazioni nel modulo time.

# time_timezone.py

import time
import os


def show_zone_info():
    print('\tTZ    :', os.environ.get('TZ', '(non impostata)'))
    print('\ttzname:', time.tzname)
    print('\tZona  : {} ({})'.format(time.timezone, (time.timezone / 3600)))
    print('\tDST   :', time.daylight)
    print('\tOra   :', time.ctime())
    print

print('Predefinito :')
show_zone_info()

ZONES = [
    'GMT',
    'Europe/Moscow',
]

for zone in ZONES:
    os.environ['TZ'] = zone
    time.tzset()
    print(zone, ':')
    show_zone_info()

Il fuso orario predefinito per l'esecuzione di questo script è Europe/Rome (fuso del traduttore - n.d.t). L'indicazione di altri fusi orari nell'esempio modificano il nome della zona (tzname), il flag dell'impostazione dell'ora legale (DST) e i valori di scostamento per quel fuso orario dal meridiano di Greenwich (Zone).

$ python3 time_timezone.py

Predefinito :
    TZ    : (non impostata)
    tzname: ('CET', 'CEST')
    Zona  : -3600 (-1.0)
    DST   : 1
    Ora   : Sun Dec 11 12:56:40 2016
GMT :
    TZ    : GMT
    tzname: ('GMT', 'GMT')
    Zona  : 0 (0.0)
    DST   : 0
    Ora   : Sun Dec 11 11:56:40 2016
Europe/Moscow :
    TZ    : Europe/Moscow
    tzname: ('MSK', 'MSK')
    Zona  : -10800 (-3.0)
    DST   : 0
    Ora   : Sun Dec 11 14:56:40 2016

Elaborare e Formattare gli Orari

Le due funzioni strptime() e strftime() si occupano della conversione tra struct_time e la rappresentazione stringa degli orari. E' a disposizione un lungo elenco di istruzioni di formattazione per supportare input e output in diversi stili. La lista completa si trova nella documentazione della libreria per il modulo time.

Questo esempio converte il tempo corrente da una stringa verso una struct_time e viceversa.

# time_strptime.py

import time


def show_struct(s):
    print('  tm_year (anno)            :', s.tm_year)
    print('  tm_mon  (mese)            :', s.tm_mon)
    print('  tm_mday (giorno del mese) :', s.tm_mday)
    print('  tm_hour (ora)             :', s.tm_hour)
    print('  tm_min  (minuti)          :', s.tm_min)
    print('  tm_sec  (secondi)         :', s.tm_sec)
    print('  tm_wday (giorno settimana):', s.tm_wday)
    print('  tm_yday (giorno nell\'anno):', s.tm_yday)
    print('  tm_isdst (flag ora legale):', s.tm_isdst)

now = time.ctime()
print('Adesso:', now)

parsed = time.strptime(now)
print('\nElaborato:')
show_struct(parsed)

print('\nFormattato:',
      time.strftime("%a %b %d %H:%M:%S %Y", parsed))

La stringa in uscita potrebbe non essere esattamente come quella in entrata, se il giorno del mese è inferiore a 10 in quanto viene prefissato da uno zero.

$ python3 time_strptime.py

Adesso: Sun Dec 11 13:10:40 2016

Elaborato:
  tm_year (anno)            : 2016
  tm_mon  (mese)            : 12
  tm_mday (giorno del mese) : 11
  tm_hour (ora)             : 13
  tm_min  (minuti)          : 10
  tm_sec  (secondi)         : 40
  tm_wday (giorno settimana): 6
  tm_yday (giorno nell'anno): 346
  tm_isdst (flag ora legale): -1

Formattato: Sun Dec 11 13:10:40 2016

Vedere anche:

time
La documentazione della libreria standard per questo modulo.
Note di portabilità per time
datetime
Il modulo datetime include altre classi per eseguire calcoli con date e ora.
calendar
Lavora con funzioni di data a più alto livello per produrre calendari o calcolare eventi ricorrenti.
Fuso orario
La pagina Wikipedia sul fuso orario