Migrerar till det nya Java 8 Date Time API

1. Översikt

I den här handledningen lär du dig hur du omformulerar din kod för att utnyttja det nya Date Time API som introducerades i Java 8.

2. Nytt API i överblick

Att arbeta med datum i Java brukade vara svårt. Det gamla datumbiblioteket från JDK innehöll endast tre klasser: java.util.Date, java.util.Calendar och java.util.Timezone .

Dessa var endast lämpliga för de mest grundläggande uppgifterna. För allt som till och med är komplicerat, utvecklarna var tvungna att använda antingen tredjepartsbibliotek eller skriva massor av anpassad kod.

Java 8 introducerade ett helt nytt Date Time API ( java.util.time. * ) Som löst bygger på det populära Java-biblioteket JodaTime. Detta nya API förenklade dramatiskt bearbetning av datum och tid och fixade många brister i det gamla datumbiblioteket.

1.1. API-klarhet

En första fördel med det nya API: et är tydlighet - API: et är mycket tydligt, koncist och lätt att förstå. Det finns inte många inkonsekvenser i det gamla biblioteket, till exempel fältnumrering (under kalendermånaderna är nollbaserade, men veckodagar är enbaserade).

1.2. API-flexibilitet

En annan fördel är flexibilitet - att arbeta med flera representationer av tid . Det gamla datumbiblioteket innehöll bara en enda tidsrepresentationsklass - java.util.Date , som trots sitt namn faktiskt är en tidsstämpel. Den lagrar bara antalet millisekunder som gått sedan Unix-epoken.

Det nya API: n har många olika tidsrepresentationer, var och en lämplig för olika användningsfall:

  • Omedelbar - representerar en tidpunkt (tidsstämpel)
  • LocalDate - representerar ett datum (år, månad, dag)
  • LocalDateTime - samma som LocalDate , men inkluderar tid med nanosekundens precision
  • OffsetDateTime - samma som LocalDateTime , men med tidszonsförskjutning
  • LocalTime - tid med nanosekundens precision och utan datuminformation
  • ZonedDateTime - samma som OffsetDateTime , men inkluderar ett tidszon-ID
  • OffsetLocalTime - samma som LocalTime , men med tidszonsförskjutning
  • MonthDay - månad och dag, utan år eller tid
  • YearMonth - månad och år, utan dag eller tid
  • Varaktighet - den tid som representeras i sekunder, minuter och timmar. Har precision i nanosekunder
  • Period - den tid som representeras i dagar, månader och år

1.3. Immutabilitet och trådsäkerhet

En annan fördel är att alla tidsrepresentationer i Java 8 Date Time API är oföränderliga och därmed trådsäkra.

Alla mutationsmetoder returnerar en ny kopia istället för att ändra originalobjektets tillstånd.

Gamla klasser som java.util.Date var inte trådsäkra och kunde introducera mycket subtila samtidiga buggar.

1.4. Metodkedjning

Alla mutationsmetoder kan kedjas ihop, vilket gör det möjligt att implementera komplexa transformationer i en enda kodrad.

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

2. Exempel

Exemplen nedan visar hur man utför vanliga uppgifter med både gammalt och nytt API.

Få aktuell tid

// Old Date now = new Date(); // New ZonedDateTime now = ZonedDateTime.now(); 

Representerar specifik tid

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

Extraherar specifika fält

// Old int month = new GregorianCalendar().get(Calendar.MONTH); // New Month month = LocalDateTime.now().getMonth(); 

Lägga till och subtrahera tid

// Old GregorianCalendar calendar = new GregorianCalendar(); calendar.add(Calendar.HOUR_OF_DAY, -5); Date fiveHoursBefore = calendar.getTime(); // New LocalDateTime fiveHoursBefore = LocalDateTime.now().minusHours(5); 

Ändra specifika fält

// Old GregorianCalendar calendar = new GregorianCalendar(); calendar.set(Calendar.MONTH, Calendar.JUNE); Date inJune = calendar.getTime(); // New LocalDateTime inJune = LocalDateTime.now().withMonth(Month.JUNE.getValue()); 

Trunkerande

Avkortning återställer alla tidsfält som är mindre än det angivna fältet. I exemplet nedan kommer minuter och allt nedan att sättas till noll

// Old Calendar now = Calendar.getInstance(); now.set(Calendar.MINUTE, 0); now.set(Calendar.SECOND, 0); now.set(Calendar.MILLISECOND, 0); Date truncated = now.getTime(); // New LocalTime truncated = LocalTime.now().truncatedTo(ChronoUnit.HOURS); 

Konvertering av tidszon

// Old GregorianCalendar calendar = new GregorianCalendar(); calendar.setTimeZone(TimeZone.getTimeZone("CET")); Date centralEastern = calendar.getTime(); // New ZonedDateTime centralEastern = LocalDateTime.now().atZone(ZoneId.of("CET")); 

Få tid mellan två tidpunkter

// Old GregorianCalendar calendar = new GregorianCalendar(); Date now = new Date(); calendar.add(Calendar.HOUR, 1); Date hourLater = calendar.getTime(); long elapsed = hourLater.getTime() - now.getTime(); // New LocalDateTime now = LocalDateTime.now(); LocalDateTime hourLater = LocalDateTime.now().plusHours(1); Duration span = Duration.between(now, hourLater); 

Tidsformatering och tolkning

DateTimeFormatter är en ersättning för den gamla SimpleDateFormat som är trådsäker och ger ytterligare funktionalitet.

// Old SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); Date now = new Date(); String formattedDate = dateFormat.format(now); Date parsedDate = dateFormat.parse(formattedDate); // New LocalDate now = LocalDate.now(); DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd"); String formattedDate = now.format(formatter); LocalDate parsedDate = LocalDate.parse(formattedDate, formatter); 

Antal dagar i en månad

// Old Calendar calendar = new GregorianCalendar(1990, Calendar.FEBRUARY, 20); int daysInMonth = calendar.getActualMaximum(Calendar.DAY_OF_MONTH); // New int daysInMonth = YearMonth.of(1990, 2).lengthOfMonth();

3. Interagera med Legacy Code

I många fall kan en användare behöva säkerställa interoperabilitet med tredjepartsbibliotek som är beroende av det gamla datumbiblioteket.

I Java har 8 gamla datumbiblioteksklasser utökats med metoder som konverterar dem till motsvarande objekt från nya Date API.

Nya klasser ger liknande funktioner.

Instant instantFromCalendar = GregorianCalendar.getInstance().toInstant(); ZonedDateTime zonedDateTimeFromCalendar = new GregorianCalendar().toZonedDateTime(); Date dateFromInstant = Date.from(Instant.now()); GregorianCalendar calendarFromZonedDateTime = GregorianCalendar.from(ZonedDateTime.now()); Instant instantFromDate = new Date().toInstant(); ZoneId zoneIdFromTimeZone = TimeZone.getTimeZone("PST").toZoneId(); 

4. Slutsats

I den här artikeln undersökte vi det nya Date Time API som finns tillgängligt i Java 8. Vi tittade på dess fördelar jämfört med det föråldrade API och pekade på skillnader med flera exempel.

Observera att vi knappt repade ytan på funktionerna i det nya Date Time API. Se till att läsa igenom den officiella dokumentationen för att upptäcka hela utbudet av verktyg som erbjuds av det nya API: et.

Kodexempel finns i GitHub-projektet.