JavaRush /Java Blog /Random-IT /Una libreria intuitiva e robusta per lavorare con orari e...
theGrass
Livello 24
Саратов

Una libreria intuitiva e robusta per lavorare con orari e date è finalmente disponibile in Java (Parte 1).

Pubblicato nel gruppo Random-IT
Java ha     finalmente un modo intuitivo e affidabile per lavorare con date e orari. I principi di data e ora sono fondamentali in molte applicazioni. Vari elementi come le date di nascita, le date di noleggio, gli orari degli eventi e gli orari di apertura dei negozi si basano tutti su date e orari, ma Java SE non ha fornito un modo conveniente per lavorarci. A partire da Java SE 8 , era disponibile una serie di pacchetti java.time , che forniscono un'API ben strutturata per lavorare con date e orari.
Sfondo
    Quando Java uscì per la prima volta, nella versione 1.0 , l'unica classe per lavorare con date e orari era java.util.Date . La prima cosa che gli sviluppatori hanno notato è che non rappresenta una “data”. In effetti, rappresenta un momento nel tempo, preciso al millisecondo, misurato a partire dalla data 1 gennaio 1970. Tuttavia, basandosi sul fatto che il metodo toString() di Date visualizza la data e l'ora nel fuso orario specificato nelle impostazioni Java della macchina , alcuni sviluppatori hanno erroneamente concluso che Date può funzionare con i fusi orari. Correggere questa classe si è rivelato così difficile (o così pigro) che nella versione 1.1 abbiamo dovuto aggiungere una nuova classe: java.util.Calendar . Sfortunatamente, la classe Calendar si è rivelata non molto migliore di Date . Ecco un piccolo elenco di problemi esistenti nella sua implementazione:
  • Variabile. Classi come data e ora dovrebbero essere immutabili.
  • Compensazioni. Gli anni nella data iniziano dal 1900, i mesi in entrambe le classi iniziano da zero.
  • Nomi. La data non è effettivamente una "data" e il calendario non è un calendario.
  • Formattazione. La formattazione funziona solo con la data, non con il calendario e non è thread-safe.
    Nel 2001 è stato creato il progetto Joda-Time . Il suo obiettivo era semplice: creare una libreria di alta qualità per lavorare con date e orari in Java . Ci è voluto del tempo, ma alla fine è stata rilasciata la versione 1.0 che è diventata rapidamente molto popolare e ampiamente utilizzata. Nel corso del tempo, gli sviluppatori hanno richiesto sempre più che una libreria di simile comodità fosse fornita come parte del JDK . Con la partecipazione di Michael Nascimento Santos dal Brasile, è stato lanciato il progetto JSR-310 , che è il processo ufficiale per la creazione e l'integrazione di una nuova API per lavorare con date e orari nel JDK .
Revisione
La nuova API java.time contiene 5 pacchetti:
  • java.time - il pacchetto base contenente oggetti per memorizzare valori
  • java.time.chrono: fornisce l'accesso a diversi calendari
  • java.time.format: formattazione e riconoscimento di data e ora
  • java.time.temporal: librerie di basso livello e funzionalità avanzate
  • java.time.zone - classi per lavorare con i fusi orari
    La maggior parte degli sviluppatori utilizzerà principalmente il pacchetto base e la formattazione e forse java.time.temporal . Pertanto, anche se sono stati aggiunti 68 nuovi tipi, gli sviluppatori ne utilizzeranno solo circa un terzo.
Date
    La classe LocalDate è una delle più importanti nella nuova API . Contiene un valore immutabile che rappresenta una data. Non è possibile impostare l'ora o il fuso orario. Il nome "locale" potrebbe esserti familiare grazie a Joda-Time e deriva originariamente dallo standard ISO-8601 . Significa proprio l'assenza di un fuso orario. Essenzialmente, LocalDate è una descrizione di una data, ad esempio "5 aprile 2014". L'ora effettiva di questa data varierà a seconda del fuso orario. Ad esempio, in Australia questa data sarà 10 ore prima rispetto a Londra e 18 ore prima rispetto a San Francisco. La classe LocalDate ha tutti i metodi comunemente necessari: LocalDate date = LocalDate.of(2014, Month.JUNE, 10); int year = date.getYear(); // 2014 Month month = date.getMonth(); // Июнь int dom = date.getDayOfMonth(); // 10 DayOfWeek dow = date.getDayOfWeek(); // Вторник int len = date.lengthOfMonth(); // 30 (дней в Июне) boolean leap = date.isLeapYear(); // false (не високосный год)     nel nostro esempio, vediamo una data creata utilizzando un metodo factory (tutti i costruttori sono privati). Successivamente chiediamo all'oggetto alcuni dati. Tieni presente che le enumerazioni Month e DayOfWeek sono progettate per rendere il codice più leggibile e affidabile. Nell'esempio seguente vedremo come modificare la data. Poiché la classe è immutabile, il risultato saranno nuovi oggetti, ma quello originale rimarrà com'era. LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.withYear(2015); // 2015-06-10 date = date.plusMonths(2); // 2015-08-10 date = date.minusDays(1); // 2015-08-09     Si tratta di modifiche relativamente semplici, ma spesso è necessario apportare modifiche alla data più complesse. Esiste un meccanismo speciale per questo nell'API java.time - TemporalAdjuster . Il suo scopo è fornire uno strumento integrato che consenta di manipolare le date, ad esempio ottenendo un oggetto corrispondente all'ultimo giorno del mese. Alcuni di essi sono inclusi nell'API , ma puoi aggiungerne di tuoi. Usare i modificatori è molto semplice, ma richiede importazioni statiche: import static java.time.DayOfWeek.* import static java.time.temporal.TemporalAdjusters.* LocalDate date = LocalDate.of(2014, Month.JUNE, 10); date = date.with(lastDayOfMonth()); date = date.with(nextOrSame(WEDNESDAY));     l'uso dei modificatori semplifica notevolmente il codice. Nessuno vuole vedere molta manipolazione manuale della data. Se qualche tipo di manipolazione della data si verifica più volte nel tuo progetto, scrivi il tuo modificatore e il tuo team potrà utilizzarlo come componente già scritto e testato.
Ora e data come valori
    Vale la pena dedicare un po' di tempo a comprendere cosa rende LocalDate un valore. I valori sono tipi di dati semplici completamente intercambiabili; quando sono uguali, l'identità degli oggetti diventa priva di significato. Un classico esempio di classe di valore è String . Confrontiamo le stringhe utilizzando equals() e non ci interessa se gli oggetti sono identici se confrontati con l' operatore == . Anche la maggior parte delle classi per lavorare con date e ore sono valori. Quindi, confrontarli utilizzando l' operatore == è una cattiva idea, come affermato nella documentazione. Per chi è interessato a saperne di più, controlla la mia recente definizione di VALJO , che delinea un insieme rigoroso di regole che gli oggetti valore in Java devono seguire , inclusa l'immutabilità, i metodi factory e la definizione corretta di equals() , hashCode , toString() , e confronta con .() .
Calendari alternativi
    La classe LocalDate , come tutte le classi principali in java.time , è legata a un singolo calendario, come descritto nello standard ISO-8601 . Lo standard 8601 descrive il calendario standard mondiale, noto anche come calendario gregoriano. Un anno standard comprende 365 giorni, un anno bisestile - 366. Ogni quarto anno è un anno bisestile a meno che non sia divisibile per 100 o sia divisibile per 400. L'anno prima del primo anno di una nuova era è considerato zero per facilità di calcolo. La prima conseguenza del fatto che questo sistema è predefinito è che i risultati non sempre corrispondono a quelli calcolati utilizzando GregorianCalendar . La classe GregorianCalendar dispone di un passaggio integrato al sistema giuliano per tutte le date precedenti al 15 ottobre 1582. Nel sistema giuliano ogni quattro anni era bisestile, senza eccezioni. La domanda è: poiché la transizione da un sistema all'altro è un fatto storico, perché java.time non lo modella? Sì, perché i diversi paesi sono passati al sistema gregoriano in tempi diversi, e considerando solo la data del passaggio vaticano otterremo dati errati per la maggior parte degli altri paesi. Ad esempio, l’Impero britannico, comprese le colonie del Nord America, passò al calendario gregoriano il 14 settembre 1752, quasi 200 anni dopo. La Russia non ha cambiato il suo calendario fino al 14 febbraio 1918, e la transizione della Svezia è generalmente una questione oscura. Di conseguenza, il significato effettivo delle date precedenti al 1918 varia notevolmente a seconda delle circostanze. Gli autori del codice LocalDate hanno preso la decisione del tutto razionale di non modellare affatto la transizione dal calendario giuliano al calendario gregoriano, per evitare discrepanze. La seconda conseguenza dell'utilizzo di ISO-8601 come calendario predefinito in tutte le classi principali è che è necessario un ulteriore set di classi per gestire i restanti calendari. L' interfaccia Cronologia è la base per lavorare con calendari alternativi, consentendoti di trovare il calendario desiderato in base al nome della lingua. Java 8 viene fornito con 4 calendari aggiuntivi: buddista tailandese, Mingguo (taiwanese), giapponese e islamico. Altri calendari potrebbero essere forniti con programmi. Ogni calendario ha una classe di data speciale come ThaiBuddhistDate , MinguoDate , JapaneseDate e HijrahDate . Ha senso utilizzarli in applicazioni altamente localizzate, come quelle per il governo giapponese. Un'interfaccia aggiuntiva, ChronoLocalDate , viene utilizzata come astrazione principale delle quattro classi precedenti insieme a LocalDate, che consente di scrivere codice indipendentemente dal tipo di calendario utilizzato. Sebbene questa astrazione esista, il suo utilizzo non è consigliato. Comprendere il motivo per cui questa astrazione non è consigliata è importante per comprendere come funziona l'intera API java.time . La conclusione è che la maggior parte del codice scritto senza riferimento a un calendario specifico risulta non funzionante. Ad esempio, non puoi essere sicuro che ci siano 12 mesi in un anno, ma alcuni sviluppatori aggiungono 12 mesi e pensano di aver aggiunto un anno intero. Non si può essere sicuri che tutti i mesi contengano approssimativamente lo stesso numero di giorni: nel calendario copto ci sono 12 mesi di 30 giorni e 1 mese di cinque o sei giorni. Inoltre, non si può essere sicuri che il numero dell'anno successivo sarà 1 in più rispetto a quello attuale, perché nel calendario giapponese gli anni si contano a partire dalla proclamazione del prossimo imperatore (in questo caso, anche 2 giorni dello stesso mese possono appartenere ad anni diversi). L'unico modo per scrivere codice funzionante e di alta qualità che funzioni con più calendari contemporaneamente è che il nucleo del codice, che esegue tutte le operazioni su date e ore, deve essere scritto utilizzando un calendario standard e solo quando si immettono/emettono date dovrebbe essere convertito in altri sistemi di calendario. Si consiglia pertanto di utilizzare LocalDate per l'archiviazione e tutte le manipolazioni delle date nell'applicazione. E solo quando localizzi le date di input e output dovresti utilizzare ChronoLocalDate , che di solito viene ottenuto dalla classe del calendario memorizzata nel profilo utente. È vero, la maggior parte delle applicazioni non necessita di una localizzazione così seria. Se hai bisogno di una spiegazione più dettagliata di tutto quanto descritto in questo capitolo, benvenuto nella documentazione della classe ChronoLocalDate .      Continuazione dell'articolo      Articolo originale
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION