Migreren naar de nieuwe Java 8 Date Time API

1. Overzicht

In deze tutorial leert u hoe u uw code kunt refactoren om gebruik te maken van de nieuwe Date Time API die in Java 8 is geïntroduceerd.

2. Nieuwe API in één oogopslag

Vroeger was het werken met datums in Java moeilijk. De oude datumbibliotheek van JDK bevatte slechts drie klassen: java.util.Date, java.util.Calendar en java.util.Timezone.

Deze waren alleen geschikt voor de meest basale taken. Voor alles wat zelfs maar enigszins complex was, moesten de ontwikkelaars bibliotheken van derden gebruiken of heel veel aangepaste code schrijven.

Java 8 introduceerde een volledig nieuwe Date Time API (java.util.time. *) die losjes is gebaseerd op de populaire Java-bibliotheek genaamd JodaTime. Deze nieuwe API heeft de verwerking van datum en tijd drastisch vereenvoudigd en veel tekortkomingen van de oude datumbibliotheek verholpen.

1.1. API-duidelijkheid

Een eerste voordeel van de nieuwe API is duidelijkheid - de API is heel duidelijk, beknopt en gemakkelijk te begrijpen. Er zijn niet veel inconsistenties gevonden in de oude bibliotheek, zoals de veldnummering (in kalendermaanden zijn op nul gebaseerd, maar dagen van week zijn op één gebaseerd).

1.2. API-flexibiliteit

Een ander voordeel is flexibiliteit - werken met meerdere weergaven van tijd. De oude datumbibliotheek bevatte slechts een enkele tijdweergaveklasse - java.util.Date, dat ondanks zijn naam eigenlijk een tijdstempel is. Het slaat alleen het aantal milliseconden op dat is verstreken sinds het Unix-tijdperk.

De nieuwe API heeft veel verschillende tijdweergaven, elk geschikt voor verschillende gebruikssituaties:

  • Onmiddellijk - vertegenwoordigt een tijdstip (tijdstempel)
  • LocalDate - staat voor een datum (jaar, maand, dag)
  • LocalDateTime - hetzelfde als LocalDate, maar omvat tijd met precisie op nanoseconde
  • OffsetDateTime - hetzelfde als LocalDateTime, maar met tijdzoneverschuiving
  • Lokale tijd - tijd met precisie op nanoseconde en zonder datuminformatie
  • ZonedDateTime - hetzelfde als OffsetDateTime, maar bevat een tijdzone-ID
  • OffsetLocalTime - hetzelfde als Lokale tijd, maar met tijdzoneverschuiving
  • Maand dag - maand en dag, zonder jaar of tijd
  • Jaar maand - maand en jaar, zonder dag of tijd
  • Looptijd - hoeveelheid tijd weergegeven in seconden, minuten en uren. Heeft een precisie van nanoseconde
  • Periode - hoeveelheid tijd weergegeven in dagen, maanden en jaren

1.3. Onveranderlijkheid en draadveiligheid

Een ander voordeel is dat alle tijdweergaven in Java 8 Date Time API dat wel zijn onveranderlijk en dus draadveilig.

Alle mutatiemethoden retourneren een nieuwe kopie in plaats van de status van het oorspronkelijke object te wijzigen.

Oude klassen zoals java.util.Date waren niet thread-safe en konden zeer subtiele concurrency-bugs introduceren.

1.4. Methodeketen

Alle mutatiemethoden kunnen aan elkaar worden geketend, waardoor complexe transformaties in één regel code kunnen worden geïmplementeerd.

ZonedDateTime nextFriday = LocalDateTime.now () .plusHours (1) .with (TemporalAdjusters.next (DayOfWeek.FRIDAY)) .atZone (ZoneId.of ("PST")); 

2. Voorbeelden

De onderstaande voorbeelden laten zien hoe u veelvoorkomende taken kunt uitvoeren met zowel de oude als de nieuwe API.

De huidige tijd krijgen

// Oude datum nu = nieuwe datum (); // Nieuwe ZonedDateTime nu = ZonedDateTime.now (); 

Vertegenwoordigt een specifieke tijd

// Old Date birthDay = nieuwe GregorianCalendar (1990, Calendar.DECEMBER, 15) .getTime (); // New LocalDate birthDay = LocalDate.of (1990, Month.DECEMBER, 15); 

Specifieke velden extraheren

// Oude int maand = nieuwe GregorianCalendar (). Get (Calendar.MONTH); // Nieuwe maand maand = LocalDateTime.now (). GetMonth (); 

Tijd optellen en aftrekken

// Oude GregorianCalendar-kalender = nieuwe GregorianCalendar (); calendar.add (Calendar.HOUR_OF_DAY, -5); Datum fiveHoursBefore = calendar.getTime (); // Nieuwe LocalDateTime fiveHoursBefore = LocalDateTime.now (). MinusHours (5); 

Specifieke velden wijzigen

// Oude GregorianCalendar-kalender = nieuwe GregorianCalendar (); calendar.set (Calendar.MONTH, Calendar.JUNE); Datum inJune = kalender.getTime (); // Nieuwe LocalDateTime inJune = LocalDateTime.now (). WithMonth (Month.JUNE.getValue ()); 

Afkappen

Bij het afkappen worden alle tijdvelden gereset die kleiner zijn dan het opgegeven veld. In het onderstaande voorbeeld worden minuten en alles hieronder op nul gezet

// Oude agenda nu = Calendar.getInstance (); now.set (Calendar.MINUTE, 0); now.set (Calendar.SECOND, 0); now.set (Calendar.MILLISECOND, 0); Datum afgekapt = now.getTime (); // New LocalTime afgekapt = LocalTime.now (). TruncatedTo (ChronoUnit.HOURS); 

Tijdzoneconversie

// Oude GregorianCalendar-kalender = nieuwe GregorianCalendar (); calendar.setTimeZone (TimeZone.getTimeZone ("CET")); Datum centralEastern = calendar.getTime (); // Nieuwe ZonedDateTime centralEastern = LocalDateTime.now (). AtZone (ZoneId.of ("CET")); 

Tijdspanne krijgen tussen twee tijdstippen

// Oude GregorianCalendar-kalender = nieuwe GregorianCalendar (); Datum nu = nieuwe datum (); calendar.add (Calendar.HOUR, 1); Datum hourLater = calendar.getTime (); lang verstreken = hourLater.getTime () - now.getTime (); // Nieuwe LocalDateTime nu = LocalDateTime.now (); LocalDateTime hourLater = LocalDateTime.now (). PlusHours (1); Duration span = Duration.between (nu, uurLater); 

Tijdopmaak en ontleden

DateTimeFormatter is een vervanging voor de oude SimpleDateFormat die thread-safe is en extra functionaliteit biedt.

// Oude SimpleDateFormat dateFormat = nieuwe SimpleDateFormat ("jjjj-MM-dd"); Datum nu = nieuwe datum (); String formattedDate = dateFormat.format (nu); Datum parsedDate = dateFormat.parse (formattedDate); // Nieuwe LocalDate nu = LocalDate.now (); DateTimeFormatter-formatter = DateTimeFormatter.ofPattern ("jjjj-MM-dd"); String formattedDate = now.format (formatter); LocalDate parsedDate = LocalDate.parse (formattedDate, formatter); 

Aantal dagen in een maand

// Oude kalenderkalender = nieuwe Gregoriaanse kalender (1990, kalender.FEBRUARI, 20); int daysInMonth = calendar.getActualMaximum (Calendar.DAY_OF_MONTH); // Nieuwe int daysInMonth = YearMonth.of (1990, 2) .lengthOfMonth ();

3. Interactie met oude code

In veel gevallen moet een gebruiker zorgen voor interoperabiliteit met bibliotheken van derden die afhankelijk zijn van de oude datumbibliotheek.

In Java zijn 8 oude datumbibliotheekklassen uitgebreid met methoden die ze converteren naar overeenkomstige objecten van de nieuwe Date API.

Nieuwe klassen bieden vergelijkbare functionaliteiten.

Instant instantFromCalendar = GregorianCalendar.getInstance (). ToInstant (); ZonedDateTime zonedDateTimeFromCalendar = nieuwe GregorianCalendar (). ToZonedDateTime (); Date dateFromInstant = Date.from (Instant.now ()); GregorianCalendar calendarFromZonedDateTime = GregorianCalendar.from (ZonedDateTime.now ()); Instant instantFromDate = nieuwe datum (). ToInstant (); ZoneId zoneIdFromTimeZone = TimeZone.getTimeZone ("PST"). ToZoneId (); 

4. Conclusie

In dit artikel hebben we de nieuwe Date Time API die beschikbaar is in Java 8 verkend. We hebben de voordelen bekeken in vergelijking met de verouderde API en hebben op verschillen gewezen aan de hand van meerdere voorbeelden.

Merk op dat we nauwelijks de mogelijkheden van de nieuwe Date Time API hebben bekrast. Zorg ervoor dat u de officiële documentatie leest om het volledige scala aan tools te ontdekken die door de nieuwe API worden aangeboden.

Codevoorbeelden zijn te vinden in het GitHub-project.