CodeGym /Corsi /JAVA 25 SELF /Panoramica dell’API java.time, differenze rispetto alle v...

Panoramica dell’API java.time, differenze rispetto alle vecchie API

JAVA 25 SELF
Livello 13 , Lezione 1
Disponibile

1. Contesto storico: come si lavorava con date e orari prima di Java 8

Nei tempi antichi (prima di Java 8) per lavorare con date e orari si usavano le classi java.util.Date, java.util.Calendar e per la formattazione — java.text.SimpleDateFormat. Era uno di quei casi in cui i programmatori di tutto il pianeta sospiravano all’unisono e, digrignando i denti, scrivevano qualcosa del tipo:

import java.util.Date;

Date now = new Date();
System.out.println(now); // Stamperà qualcosa di strano come "Wed Jun 05 14:15:22 MSK 2025"

Sembra semplice, ma in realtà non era così roseo. Ecco solo alcune delle «gioie» delle vecchie API:

  • Date è un oggetto mutabile (mutable). Si poteva modificarlo accidentalmente e questo spesso portava a bug.
  • I mesi in Date e Calendar partivano da zero (gennaio è 0, dicembre — 11), mentre i giorni partivano da uno.
  • SimpleDateFormat non era thread-safe: se due thread formattavano una data contemporaneamente, si potevano ottenere risultati inattesi.
  • Un’enorme quantità di metodi era contrassegnata come @Deprecated (obsoleti), e l’IDE vi spaventava continuamente con avvisi gialli.
  • La gestione dei fusi orari era un vero dolore: era facile confondere l’ora locale con l’UTC, e del passaggio all’ora legale/solare è meglio non parlare.

Esempio doloroso

import java.util.Date;

Date date = new Date(2025, 5, 1); // anno 2025, mese 5 (giugno?), giorno 1
System.out.println(date); // Non quello che ti aspetti!

2. Comparsa di java.time: un nuovo approccio

Entro il 2014 era chiaro: le vecchie API non erano solo scomode — erano pericolose. Per questo in Java è nato il nuovo package — java.time, che implementa la specifica JSR‑310. Questa API è stata ispirata dalla popolare libreria Joda-Time ed è diventata subito lo standard de facto.

Principali package e classi

  • java.time — il package principale, dove vivono tutte le nuove classi per date e orari.
  • java.time.format — per formattare e fare il parsing di date e orari.
  • java.time.temporal — per operazioni temporali più avanzate.
  • java.time.zone — per lavorare con i fusi orari.

Ecco i protagonisti della nuova API:

Classe A cosa serve? Esempio di utilizzo
LocalDate
Solo data (anno, mese, giorno) Compleanno, senza orario
LocalTime
Solo ora (ore, minuti, secondi) Orario di un incontro, senza data
LocalDateTime
Data e ora, senza fuso orario Evento locale
ZonedDateTime
Data e ora con fuso orario Incontro a Minsk all’ora locale
Instant
Punto temporale assoluto (UTC) Timestamp di un evento nel log
Duration
Intervallo di tempo (ore, minuti, sec.) Durata di una chiamata
Period
Periodo (anni, mesi, giorni) Anzianità lavorativa, età

Esempio: creare una data nel nuovo modo

import java.time.LocalDate;

LocalDate today = LocalDate.now();
System.out.println(today); // Ad esempio, "2025-06-05"

3. Vantaggi del nuovo API

Immutabilità (immutable)

Tutte le classi di java.time sono immutabili. Significa che se create un oggetto LocalDate, non potete modificarlo. Ogni operazione (ad esempio, aggiungere un giorno) restituisce un nuovo oggetto.

LocalDate today = LocalDate.now();
LocalDate tomorrow = today.plusDays(1);

System.out.println(today);    // 2025-06-05
System.out.println(tomorrow); // 2025-06-06

Gestione esplicita dei fusi orari

Con le vecchie API era facile dimenticare in quale fuso orario si trovasse una data. In java.time è tutto esplicito: se serve il fuso orario — usate ZonedDateTime, se non serve — usate LocalDateTime.

import java.time.ZonedDateTime;
import java.time.ZoneId;

ZonedDateTime MinskTime = ZonedDateTime.now(ZoneId.of("Europe/Minsk"));
System.out.println(MinskTime); // 2025-06-05T14:23:45+03:00[Europe/Minsk]

Metodi comodi per calcoli e confronti

LocalDate today = LocalDate.now();
LocalDate nextMonth = today.plusMonths(1);
boolean isAfter = LocalDate.now().plusDays(1).isAfter(today); // true

Formattazione e parsing

Formattazione e parsing — tramite DateTimeFormatter (in dettaglio — nella prossima lezione):

import java.time.format.DateTimeFormatter;

LocalDate today = LocalDate.now();
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd.MM.yyyy");
String formatted = today.format(formatter); // "05.08.2025"

4. Compatibilità: come convivere con il codice vecchio

Nel mondo reale molto spesso bisogna lavorare con librerie o sistemi legacy che usano Date e Calendar. Per fortuna, la nuova API è amichevole con l’eredità: si possono convertire i tipi vecchi in nuovi e viceversa.

Conversione DateInstant

import java.util.Date;
import java.time.Instant;

// Date → Instant
Date legacyDate = new Date();
Instant instant = legacyDate.toInstant();

// Instant → Date
Date dateBack = Date.from(instant);

Conversione CalendarZonedDateTime

import java.util.Calendar;
import java.time.ZonedDateTime;
import java.time.ZoneId;
import java.util.Date;

// Calendar → ZonedDateTime
Calendar calendar = Calendar.getInstance();
ZonedDateTime zdt = ZonedDateTime.ofInstant(
        calendar.toInstant(),
        calendar.getTimeZone().toZoneId()
);

// ZonedDateTime → Calendar
Calendar calBack = Calendar.getInstance();
calBack.setTime(Date.from(zdt.toInstant()));

Tabella: mappatura tra classi vecchie e nuove

Classe vecchia Classe nuova Commento
java.util.Date
Instant
Tempo assoluto
java.util.Calendar
ZonedDateTime
Data e ora con fuso orario
java.text.SimpleDateFormat
DateTimeFormatter
Formattazione/parsing delle date

5. Pratica: primi passi con java.time

Supponiamo di avere un utente con una data di nascita. Salviamo e stampiamo questa data:

import java.time.LocalDate;

public class UserProfile {
    private String name;
    private LocalDate birthDate;

    public UserProfile(String name, LocalDate birthDate) {
        this.name = name;
        this.birthDate = birthDate;
    }

    public void printProfile() {
        System.out.println("Nome: " + name);
        System.out.println("Data di nascita: " + birthDate);
    }
}

public class Main {
    public static void main(String[] args) {
        UserProfile user = new UserProfile("Alisa", LocalDate.of(1998, 12, 25));
        user.printProfile();
    }
}

Output:

Nome: Alisa
Data di nascita: 1998-12-25

6. Confronto: vecchio API vs nuovo API

Esempio: aggiungere una settimana alla data di nascita

Metodo vecchio (Date/Calendar):

import java.util.Calendar;

Calendar cal = Calendar.getInstance();
cal.set(1998, Calendar.DECEMBER, 25);
cal.add(Calendar.WEEK_OF_YEAR, 1);
System.out.println(cal.getTime()); // Macchinoso e poco chiaro

Metodo nuovo (java.time):

import java.time.LocalDate;

LocalDate birthDate = LocalDate.of(1998, 12, 25);
LocalDate nextWeek = birthDate.plusWeeks(1);
System.out.println(nextWeek); // 1999-01-01

Con il nuovo API il codice è più corto, più semplice e più sicuro.

7. Errori tipici nell’uso di java.time

Errore n. 1: dimenticare che gli oggetti sono immutabili.
Se chiamate date.plusDays(1); e non salvate il risultato, la data originale rimarrà invariata.

Errore n. 2: confusione tra LocalDate e LocalDateTime.
LocalDate contiene solo la data (anno, mese, giorno), mentre LocalDateTime include anche l’ora. Non confondeteli se dovete gestire ore e minuti.

Errore n. 3: usare le classi vecchie nei nuovi progetti.
Se possibile — usate sempre java.time. Le classi vecchie servono solo per compatibilità.

Errore n. 4: gestione errata dei fusi orari.
Se dovete memorizzare un evento rilevante per regioni diverse, usate ZonedDateTime o almeno Instant. LocalDateTime non contiene informazioni sul fuso orario!

Errore n. 5: tentare di confrontare direttamente LocalDate e LocalDateTime.
Sono tipi diversi; non si possono confrontare direttamente. Prima convertiteli allo stesso tipo.

Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION