CodeGym /Corsi /C# SELF /Lavorare con i fusi orari:

Lavorare con i fusi orari: TimeZoneInfo

C# SELF
Livello 15 , Lezione 2
Disponibile

1. Introduzione

Se pensi che i fusi orari siano solo "aggiungere/togliere qualche ora", molto presto sentirai tutto il dolore della maggior parte dei programmatori sul pianeta. Fusi orari, cambi d'orario tra ora legale/solare, eccezioni strane quando provi a "trasformare l'orario in un'altra regione" — tutto questo può portare a bug difficili da trovare e ancora più difficili da spiegare agli utenti.

La cosa più assurda: nel mondo non esiste e non è mai esistita una "comprensione universale" del tempo — per esempio, due paesi vicini possono gestire il cambio all'ora legale in modo diverso, e a volte le decisioni vengono prese a metà anno (sì, succede davvero!). Esempio: nel 2011 Samoa ha "saltato" un giorno intero e cambiato lato rispetto alla linea del cambio data.

Ma C# e .NET ti danno strumenti potenti per almeno provarci. Oggi conosceremo il nostro salvatore — il tipo TimeZoneInfo e le sue funzioni che aiuteranno te e la tua app.

Quando e perché ti serve lavorare con i fusi orari

  • Quando utenti/server si trovano in regioni diverse del mondo
  • Quando salvi data e ora nel database in UTC, ma mostri all'utente nel suo orario locale
  • Per calcolare orari di eventi, promemoria, eventi online ("Il webinar inizia alle 19:00 a Berlino — e nel tuo fuso?")
  • Quando sviluppi sistemi aziendali/globali (tipo contabilità o CRM per business internazionali)

Panoramica del tipo TimeZoneInfo

TimeZoneInfo è una classe creata apposta in .NET per rappresentare le info su un fuso orario: offset rispetto a UTC, nome, supporto per l'ora legale ecc.

Diversamente dalla vecchia classe TimeZone, che conosce solo il fuso "locale" e "UTC", TimeZoneInfo ti dà accesso completo a tutti i fusi orari registrati nel sistema (e anche a quelli creati a mano).

2. Ottenere info sui fusi orari

Fuso locale e UTC

Ottenere info sul fuso orario locale è facilissimo:


// Locale (cioè dove gira il tuo programma)
TimeZoneInfo local = TimeZoneInfo.Local;

// Sempre UTC
TimeZoneInfo utc = TimeZoneInfo.Utc;

Console.WriteLine(local.DisplayName); // Per esempio: (UTC+01:00) Berlino, Vienna
Console.WriteLine(utc.DisplayName);   // (UTC) Coordinated Universal Time

Tutti i fusi orari disponibili

Spesso serve mostrare all'utente la lista di tutti i fusi orari possibili (tipo quando si registra a un servizio):


foreach (var tz in TimeZoneInfo.GetSystemTimeZones())
{
    Console.WriteLine($"{tz.Id} | {tz.DisplayName}");
}

Questo stampa una lista tipo:

  • Central European Standard Time | (UTC+01:00) Berlino, Vienna
  • Pacific Standard Time | (UTC-08:00) Pacific Time (US & Canada)
  • ecc.

Visualizzazione: proprietà principali di TimeZoneInfo

Proprietà Descrizione
Id
Identificatore di sistema del fuso orario (usato per la ricerca)
DisplayName
Descrizione per l'utente (con orari e città)
StandardName
Nome dell'orario "standard"
DaylightName
Nome dell'orario durante l'ora legale
BaseUtcOffset
Offset rispetto a UTC (tipo, +01:00 per Berlino)
SupportsDaylightSavingTime
True se il fuso supporta il cambio tra ora legale/solare

3. Conversione dell'orario tra fusi orari

Ecco perché serve tutto questo! Devi:

  • Convertire l'orario da una zona all'altra (tipo, il server salva in UTC, ma mostri all'utente nel suo fuso)
  • Gestire correttamente il cambio tra ora legale/solare

Sintassi generale


DateTime utcNow = DateTime.UtcNow;

// Per esempio, convertiamo quest'orario nel fuso dell'Europa centrale
TimeZoneInfo europeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time");
DateTime europeTime = TimeZoneInfo.ConvertTimeFromUtc(utcNow, europeZone);

Console.WriteLine($"UTC now: {utcNow}");       // 2024-06-20 10:30:00
Console.WriteLine($"Europe now: {europeTime}"); // 2024-06-20 11:30:00

Importante: Usa sempre UTC per i calcoli e il salvataggio interno, e solo "in uscita" converti nel fuso giusto!

Come trovare l'identificatore del fuso orario?

Su Windows gli identificatori (Id) dei fusi sono specifici (tipo "Central European Standard Time"), mentre su Linux/Unix di solito sono IANA/Olson ("Europe/Berlin", "America/New_York").

Puoi ottenere la lista degli identificatori sul tuo sistema con TimeZoneInfo.GetSystemTimeZones().

4. Conversione tra zone arbitrarie

Supponiamo che tu abbia un orario di Londra (GMT/UTC+0) e vuoi convertirlo in Tokyo (UTC+9):


DateTime londonTime = new DateTime(2024, 6, 20, 12, 0, 0, DateTimeKind.Unspecified);

TimeZoneInfo londonZone = TimeZoneInfo.FindSystemTimeZoneById("GMT Standard Time");
TimeZoneInfo tokyoZone  = TimeZoneInfo.FindSystemTimeZoneById("Tokyo Standard Time");

// Primo passo: converti l'orario in UTC (se è locale)
DateTime utc = TimeZoneInfo.ConvertTimeToUtc(londonTime, londonZone);

// Secondo passo: converti UTC nell'orario di Tokyo
DateTime tokyoTime = TimeZoneInfo.ConvertTimeFromUtc(utc, tokyoZone);

Console.WriteLine($"London: {londonTime} | UTC: {utc} | Tokyo: {tokyoTime}");

Gestire i cambi tra ora legale e solare

TimeZoneInfo tiene conto dei cambi tra ora legale/solare — se il fuso lo supporta.


TimeZoneInfo eastern = TimeZoneInfo.FindSystemTimeZoneById("Eastern Standard Time");

DateTime dateWinter = new DateTime(2024, 1, 1, 12, 0, 0, DateTimeKind.Unspecified);
DateTime dateSummer = new DateTime(2024, 7, 1, 12, 0, 0, DateTimeKind.Unspecified);

Console.WriteLine( TimeZoneInfo.ConvertTimeToUtc(dateWinter, eastern)); // Offset UTC-5
Console.WriteLine( TimeZoneInfo.ConvertTimeToUtc(dateSummer, eastern)); // Offset UTC-4 — ora legale!

Anche se gli USA (nell'esempio sopra) decidessero di abolire l'ora legale (e ogni anno ci provano!), il database dei fusi nella tua OS verrà comunque aggiornato e il tuo codice funzionerà bene.

5. Consigli pratici ed errori comuni

Eccezioni e trappole

  • Nei momenti in cui si cambia orario (tipo le 2:30 di notte nel giorno del cambio tra ora legale/solare), certi orari possono essere "inesistenti" o "ripetuti":
    Per esempio, nel giorno del cambio "indietro" le 2:30 succedono due volte — e sono "diverse"!
  • Attenzione: la lista dei fusi può cambiare con gli aggiornamenti della OS! Esempio: alcuni paesi aboliscono/introducono l'ora legale.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION