CodeGym /Corsi /C# SELF /Tipi principali per lavorare con il tempo

Tipi principali per lavorare con il tempo

C# SELF
Livello 15, Lezione 0
Disponibile

1. Introduzione al tipo DateTime

Data e ora sono un mattone fondamentale di qualsiasi business logic, non puoi ignorarli nemmeno nei progetti più semplici. Spesso serve sapere quando un utente si è registrato, quando inviare una mail, gestire correttamente gli orari dei voli, i fusi orari — ovunque ci sono date! Ma, come spesso succede, lavorare con data e ora è uno degli argomenti più insidiosi nella programmazione. 😅

C# offre due tipi davvero importanti per lavorare col tempo: DateTime e DateTimeOffset. In breve — uno per scenari semplici, l’altro per problemi legati ai fusi orari e alla memorizzazione precisa del tempo.

Cos’è DateTime?

Il tipo DateTime è una struct definita nello spazio dei nomi System. Serve per memorizzare data e ora con una precisione fino a 100 nanosecondi (un decimo di miliardesimo di secondo).

  • È un tipo valore (struct), quindi viene copiato per valore.
  • Contiene sia la data che l’ora.
  • Permette di salvare solo la data (2025-05-24) oppure data e ora (2025-05-24 15:17:42).
  • “Non sa” nulla dei fusi orari, a meno che non venga specificato esplicitamente.

2. Creare un DateTime

Ci sono diversi modi, vediamo i principali.

1. Data e ora attuali

DateTime now = DateTime.Now;           // Ora locale del computer
DateTime utcNow = DateTime.UtcNow;     // Ora di Greenwich (UTC)
  • Now — è “come sul tuo computer”, tiene conto del fuso orario locale di Windows.
  • UtcNow — “universale”, cioè Coordinated Universal Time. Molto comodo per salvare orari, ad esempio, nei database o in sistemi che lavorano in tutto il mondo.

2. Costruttori

// Anno, mese, giorno
var date1 = new DateTime(2025, 5, 24);

// Anno, mese, giorno, ore, minuti, secondi
var date2 = new DateTime(2025, 5, 24, 12, 0, 0);

// Anno, mese, giorno, ore, minuti, secondi, millisecondi
var date3 = new DateTime(2025, 5, 24, 12, 0, 0, 500);

I mesi non partono da zero! Quindi gennaio è 1, dicembre è 12.

3. Parsing da stringa

Spesso la data arriva come stringa! Ad esempio, l’utente inserisce la data a mano.

string userInput = "2025-05-24 18:30";
DateTime parsed = DateTime.Parse(userInput); // Può lanciare un’eccezione!

Per un parsing sicuro — usiamo TryParse:

string input = "2025-05-24 18:30";
if (DateTime.TryParse(input, out DateTime result))
{
    Console.WriteLine($"Convertito con successo: {result}");
}
else
{
    Console.WriteLine("Impossibile convertire la stringa in data.");
}

4. Ottenere la data “senza ora”

DateTime today = DateTime.Today; // Giorno corrente, ma ora = 00:00:00

Estrarre componenti di data e ora

Tutte le proprietà si ottengono al volo:

var dt = new DateTime(2025, 5, 24, 15, 17, 42);

int year = dt.Year;         // 2025
int month = dt.Month;       // 5 (maggio)
int day = dt.Day;           // 24
int hour = dt.Hour;         // 15
int minute = dt.Minute;     // 17
int second = dt.Second;     // 42
DayOfWeek dow = dt.DayOfWeek; // Venerdì

3. Lavorare con il tipo DateTime

Somma e sottrazione di date

Il tempo in programmazione vola, e per non dover calcolare “quante ore mancano alla deadline”, usiamo i metodi della classe:

DateTime now = DateTime.Now;
DateTime tomorrow = now.AddDays(1); // Domani
DateTime afterFiveHours = now.AddHours(5); // Tra 5 ore
DateTime inTenMinutes = now.AddMinutes(10); // Tra 10 minuti

Differenza tra due date: TimeSpan

La differenza tra due date è una grandezza a parte, tipo TimeSpan:

DateTime deadline = new DateTime(2026, 6, 1);
DateTime now = DateTime.Now;

TimeSpan untilDeadline = deadline - now;

Console.WriteLine($"Giorni rimasti alla deadline: {untilDeadline.Days}");
Console.WriteLine($"Ore rimaste alla deadline: {untilDeadline.TotalHours:N2}");

TimeSpan — è una “differenza”, non una “data/ora specifica”!

Controllare se una data è nel futuro/passato

if (deadline > now)
    Console.WriteLine("La deadline è ancora davanti!");
else
    Console.WriteLine("La deadline è già passata! Consegna subito il lavoro!");

4. Come vengono salvate le date sotto il cofano

Per facilitare somme e sottrazioni tra date, i programmatori hanno deciso di salvare tutte le date come numero di secondi passati dall’inizio della nostra era. Valori del range:

Proprietà Valore
Data minima
DateTime.MinValue
= 0001-01-01 00:00:00
Data massima
DateTime.MaxValue
= 9999-12-31 23:59:59.9999999
Unità di misura 1 tick = 100 nanosecondi

DateTime non salva solo il numero di secondi, ma il numero di “tick” (ticks) da una data speciale — 1 gennaio 0001 (eh sì, i programmatori non sanno dei dinosauri, il loro calendario è più rigido). Un tick = 100 nanosecondi.

5. Tipo DateTimeOffset

A volte il tipo DateTime non basta. Vediamo il caso classico: un’azienda lavora in due paesi, hanno fusi orari diversi, e tutti gli appuntamenti sono fissati “secondo il mio orario”. Come si fa?

L’ora salvata come DateTime spesso è “astratta”: è solo una serie di numeri e tick, finché non dici esplicitamente in quale zona era. Ad esempio, se ricevi "2025-05-24 15:00", non puoi essere sicuro — è l’ora di Nairobi? Baghdad? Berlino? (e se c’è anche l’ora legale — tieniti forte!).

Perciò, per problemi dove serve il momento preciso nel tempo, non solo la “data del calendario”, è nato il secondo tipo — DateTimeOffset. Creare un DateTimeOffset specificando l’offset (ad esempio, Nairobi +3 rispetto a UTC):


var localTime = new DateTimeOffset(2025, 5, 24, 15, 0, 0, TimeSpan.FromHours(3));

Usa DateTimeOffset se:

  • Devi sapere il momento preciso (ad esempio, per eventi nei log legati all’ora del server).
  • L’app lavora con utenti in diversi fusi orari.
  • Devi salvare/trasmettere l’ora con il fuso (ad esempio, per transazioni, eventi, orari).

6. Come creare un DateTimeOffset?

  1. Momento attuale
    DateTimeOffset now = DateTimeOffset.Now; // Ora locale + offset
    DateTimeOffset utc = DateTimeOffset.UtcNow; // UTC (offset 0)
    
  2. Creazione esplicita
    // Anno, mese, giorno, ora, minuto, secondo, offset (ad esempio, +2 ore)
    DateTimeOffset custom = new DateTimeOffset(2025, 5, 24, 20, 0, 0, TimeSpan.FromHours(2));
    
  3. Conversione da DateTime
    DateTime dt = DateTime.Now;
    DateTimeOffset dto = new DateTimeOffset(dt); // L’offset locale viene preso automaticamente
    

Estrarre componenti

DateTimeOffset dto = DateTimeOffset.Now;
var datePart = dto.Date;      // Solo la data
var timePart = dto.TimeOfDay; // Solo l’ora
var offset = dto.Offset;      // Offset rispetto a UTC, ad esempio, 03:00:00

Conversione tra fusi orari

Magia degli offset:

// Ottieni la data in UTC
var now = DateTimeOffset.Now;
var utc = now.ToUniversalTime();
Console.WriteLine(utc); // Ora di Greenwich

// Converti in un altro fuso
var berlinTime = utc.ToOffset(TimeSpan.FromHours(2));
Console.WriteLine(berlinTime); // Per Berlino (CET +2)

7. Quando usare DateTime e quando DateTimeOffset?

Filosofia della scelta

Quando si tratta di qualcosa di semplice e locale — tipo compleanno, data di pubblicazione di un articolo o deadline per un sondaggio entro le 15:00, di solito basta DateTime. In questi casi il tempo assoluto non è critico, conta solo che l’evento sia avvenuto in un certo giorno e ora, senza legarsi al fuso orario.

Ma se serve fissare un momento preciso tenendo conto del fuso, ad esempio, nei log, nelle transazioni o nei sistemi distribuiti — meglio usare DateTimeOffset. Così non ti incasini quando passi l’ora tra sistemi diversi, soprattutto se sono in fusi orari diversi.

Scenario Tipo Perché
Compleanno
DateTime
Conta solo la data, il fuso non importa (di solito)
Ora del login
DateTimeOffset
Serve sapere il momento preciso e l’offset
Scadenza prodotto
DateTime
Data di fine, il fuso non importa
Ora di un evento nel log
DateTimeOffset
Meglio sempre salvare con offset
2
Compito
C# SELF, livello 15, lezione 0
Bloccato
Stampa della data e dell'ora attuali in diversi formati
Stampa della data e dell'ora attuali in diversi formati
2
Compito
C# SELF, livello 15, lezione 0
Bloccato
Aggiunta e sottrazione del tempo
Aggiunta e sottrazione del tempo
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION