Migrácia na nové rozhranie Java 8 Date Time API
1. Prehľad
V tomto tutoriáli sa dozviete, ako refaktorovať váš kód, aby ste využili nové rozhranie Date Time API zavedené v prostredí Java 8.
2. Nové API v skratke
Práca s dátumami v Jave bývala ťažká. Stará knižnica dátumov poskytovaná JDK obsahovala iba tri triedy: java.util.Date, java.util.Calendar a java.util.Timezone.
Boli vhodné iba na najzákladnejšie úlohy. Pre všetko, čo je aj vzdialene zložité, museli vývojári použiť buď knižnice tretích strán, alebo napísať kopu vlastného kódu.
Java 8 predstavila úplne nové rozhranie Date Time API (java.util.time. *), ktorý je voľne založený na populárnej knižnici Java s názvom JodaTime. Toto nové API dramaticky zjednodušilo spracovanie dátumu a času a opravilo veľa nedostatkov starej knižnice dátumov.
1.1. Zrozumiteľnosť API
Prvá výhoda nového API je jasnosť - API je veľmi jasné, stručné a ľahko pochopiteľné. Neobsahuje veľa nezrovnalostí v starej knižnici, napríklad číslovanie polí (v Kalendári sú mesiace založené na nule, ale dni v týždni sú založené na jednom).
1.2. Flexibilita API
Ďalšou výhodou je flexibilita - práca s viacerými reprezentáciami času. Stará knižnica dátumov obsahovala iba jednu triedu reprezentácie času - java.util.Date, ktorý je napriek svojmu názvu v skutočnosti časovou značkou. Ukladá iba počet milisekúnd, ktoré uplynuli od epochy Unixu.
Nové API má veľa rôznych časových reprezentácií, z ktorých každá je vhodná pre rôzne prípady použitia:
- Okamžité - predstavuje časový bod (časová značka)
- LocalDate - predstavuje dátum (rok, mesiac, deň)
- LocalDateTime - rovnaké ako LocalDate, ale zahŕňa čas s presnosťou na nanosekundy
- OffsetDateTime - rovnaké ako LocalDateTime, ale s posunom časového pásma
- Miestny čas - čas s presnosťou na nanosekundy a bez informácií o dátume
- ZonedDateTime - rovnaké ako OffsetDateTime, ale obsahuje ID časového pásma
- OffsetLocalTime - rovnaké ako Miestny čas, ale s posunom časového pásma
- MonthDay - mesiac a deň, bez roku alebo času
- RokMesiac - mesiac a rok bez dňa alebo času
- Trvanie - množstvo času vyjadrené v sekundách, minútach a hodinách. Má presnosť nanosekúnd
- Obdobie - množstvo času vyjadrené v dňoch, mesiacoch a rokoch
1.3. Nezmeniteľnosť a bezpečnosť závitov
Ďalšou výhodou je, že všetky časové reprezentácie v rozhraní Java 8 Date Time API sú nemenné a teda bezpečné pre vlákna.
Všetky mutujúce metódy vrátia novú kópiu namiesto úpravy stavu pôvodného objektu.
Staré triedy ako napr java.util.Date neboli bezpečné pre vlákna a mohli by zaviesť veľmi jemné chyby súbežnosti.
1.4. Metóda reťazenia
Všetky metódy mutácie je možné spojiť dohromady, čo umožňuje implementovať komplexné transformácie v jednom riadku kódu.
ZonedDateTime nextFriday = LocalDateTime.now () .plusHours (1) .with (TemporalAdjusters.next (DayOfWeek.FRIDAY)) .atZone (ZoneId.of ("PST"));
2. Príklady
Nasledujúce príklady ukážu, ako vykonávať bežné úlohy so starým aj novým API.
Získava sa aktuálny čas
// Teraz starý dátum = nový dátum (); // Nový ZonedDateTime now = ZonedDateTime.now ();
Predstavuje konkrétny čas
// Starý dátum birthDay = nový GregorianCalendar (1990, Calendar.DECEMBER, 15) .getTime (); // Nové LocalDate birthDay = LocalDate.of (1990, Month.DECEMBER, 15);
Extrahovanie konkrétnych polí
// Starý int mesiac = nový GregorianCalendar (). Get (Calendar.MONTH); // Nový mesiac mesiac = LocalDateTime.now (). GetMonth ();
Sčítanie a odčítanie času
// Starý kalendár GregorianCalendar = nový GregorianCalendar (); calendar.add (Calendar.HOUR_OF_DAY, -5); Dátum fiveHoursBefore = calendar.getTime (); // Nový LocalDateTime fiveHoursBefore = LocalDateTime.now (). MinusHours (5);
Zmena konkrétnych polí
// Starý kalendár GregorianCalendar = nový GregorianCalendar (); calendar.set (Calendar.MONTH, Calendar.JUNE); Dátum inJune = calendar.getTime (); // Nový LocalDateTime inJune = LocalDateTime.now (). WithMonth (Month.JUNE.getValue ());
Orezávanie
Skrátením sa resetujú všetky časové polia menšie ako zadané pole. V príklade uvedenom nižšie budú všetky minúty nižšie a nastavia sa na nulu
// Starý kalendár teraz = Calendar.getInstance (); now.set (Calendar.MINUTE, 0); now.set (Calendar.SECOND, 0); now.set (Calendar.MILLISECOND, 0); Dátum skrátený = now.getTime (); // Nový LocalTime truncated = LocalTime.now (). TruncatedTo (ChronoUnit.HOURS);
Prepočet časového pásma
// Starý kalendár GregorianCalendar = nový GregorianCalendar (); calendar.setTimeZone (TimeZone.getTimeZone ("CET")); Dátum centralEastern = calendar.getTime (); // Nový ZonedDateTime centralEastern = LocalDateTime.now (). AtZone (ZoneId.of ("CET"));
Získanie časového rozpätia medzi dvoma časovými bodmi
// Starý kalendár GregorianCalendar = nový GregorianCalendar (); Dátum teraz = nový Dátum (); calendar.add (Calendar.HOUR, 1); Dátum hourLater = calendar.getTime (); dlho uplynul = hourLater.getTime () - teraz.getTime (); // Nový LocalDateTime now = LocalDateTime.now (); LocalDateTime hourLater = LocalDateTime.now (). PlusHours (1); Duration span = Duration.b Between (now, hourLater);
Formátovanie a analýza času
DateTimeFormatter je náhrada za starý SimpleDateFormat, ktorý je bezpečný pre vlákna a poskytuje ďalšie funkcie.
// Starý SimpleDateFormat dateFormat = nový SimpleDateFormat ("rrrr-MM-dd"); Dátum teraz = nový Dátum (); Reťazec formattedDate = dateFormat.format (teraz); Dátum parsedDate = dateFormat.parse (formattedDate); // Nový LocalDate now = LocalDate.now (); DateTimeFormatter formatter = DateTimeFormatter.ofPattern ("rrrr-MM-dd"); Reťazec formattedDate = now.format (formatter); LocalDate parsedDate = LocalDate.parse (formattedDate, formatter);
Počet dní v mesiaci
// Starý kalendár kalendára = nový GregorianCalendar (1990, Calendar.FEBRUARY, 20); int daysInMonth = calendar.getActualMaximum (Calendar.DAY_OF_MONTH); // New int daysInMonth = YearMonth.of (1990, 2) .lengthOfMonth ();
3. Interakcia so starým kódom
V mnohých prípadoch môže byť potrebné, aby používateľ zabezpečil interoperabilitu s knižnicami tretích strán, ktoré sa spoliehajú na starú knižnicu dátumov.
V Jave 8 boli staré triedy knižníc dátumov rozšírené o metódy, ktoré ich prevádzajú na zodpovedajúce objekty z nového rozhrania Date API.
Nové triedy poskytujú podobné funkcie.
Okamžité instantFromCalendar = GregorianCalendar.getInstance (). ToInstant (); ZonedDateTime zonedDateTimeFromCalendar = nový GregorianCalendar (). ToZonedDateTime (); Dátum dateFromInstant = Date.from (Instant.now ()); GregorianCalendar calendarFromZonedDateTime = GregorianCalendar.from (ZonedDateTime.now ()); Okamžité instantFromDate = nový dátum (). ToInstant (); ZoneId zoneIdFromTimeZone = TimeZone.getTimeZone ("PST"). ToZoneId ();
4. Záver
V tomto článku sme preskúmali nové rozhranie Date Time API dostupné v prostredí Java 8. Pozreli sme sa na jeho výhody v porovnaní so zastaraným API a na niekoľko príkladov sme poukázali na rozdiely.
Upozorňujeme, že sme sotva poškriabali povrch schopností nového rozhrania Date Time API. Prečítajte si oficiálnu dokumentáciu a objavte celú škálu nástrojov, ktoré ponúka nové API.
Príklady kódov nájdete v projekte GitHub.