Introduktion til Java 8 Date / Time API

1. Oversigt

Java 8 introducerede nye API'er til Dato og Tid for at afhjælpe de ældres mangler java.util.Date og java.util.Kalender.

Som en del af denne artikel, lad os starte med problemerne i den eksisterende Dato og Kalender API'er og lad os diskutere, hvordan den nye Java 8 Dato og Tid API'er adresserer dem.

Vi vil også se på nogle af kerneklasserne i det nye Java 8-projekt, der er en del af java.tid pakke som LocalDate, LocalTime, LocalDateTime, ZonedDateTime, periode, varighed og deres understøttede API'er.

2. Problemer med det eksisterende Dato/Tid API'er

  • Trådsikkerhed - Det Dato og Kalender klasser er ikke trådsikre, hvilket efterlader udviklere til at håndtere hovedpine ved problemer med at debugge samtidige problemer og at skrive yderligere kode til håndtering af trådsikkerhed. Tværtimod det nye Dato og Tid API'er introduceret i Java 8 er uforanderlige og trådsikre og fjerner dermed den samtidige hovedpine fra udviklere.
  • API design og let forståelse - Det Dato og Kalender API'er er dårligt designet med utilstrækkelige metoder til at udføre daglige operationer. Den nye Dato tid API'er er ISO-centreret og følger ensartede domænemodeller for dato, tid, varighed og perioder. Der er en lang række anvendelsesmetoder, der understøtter de mest almindelige operationer.
  • Zonedate og Tid - Udviklere måtte skrive yderligere logik for at håndtere tidszonelogik med de gamle API'er, mens med de nye API'er kan håndtering af tidszone gøres med Lokal og Zonedate/Tid API'er.

3. Brug LocalDate, Lokal tid og LocalDateTime

De mest anvendte klasser er LocalDate, Lokal tid og LocalDateTime. Som deres navne indikerer, repræsenterer de den lokale dato / tid fra observatørens kontekst.

Disse klasser bruges hovedsageligt, når det ikke kræves, at tidszone specifikt specificeres i sammenhængen. Som en del af dette afsnit dækker vi de mest almindeligt anvendte API'er.

3.1. Arbejder med LocalDate

Det LocalDate repræsenterer en dato i ISO-format (åååå-MM-dd) uden tid.

Det kan bruges til at gemme datoer som fødselsdage og betalingsdage.

En forekomst af aktuel dato kan oprettes fra systemuret som nedenfor:

LocalDate localDate = LocalDate.now ();

Det LocalDate der repræsenterer en bestemt dag, måned og år kan fås ved hjælp af “af”-Metoden eller ved hjælp af“parse”Metode. For eksempel repræsenterer nedenstående kodestykker LocalDate for 20. februar 2015:

LocalDate.of (2015, 02, 20); LocalDate.parse ("2015-02-20");

Det LocalDate giver forskellige hjælpemetoder til at få en række oplysninger. Lad os kigge hurtigt på nogle af disse API-metoder.

Følgende kodestykke henter den aktuelle lokale dato og tilføjer en dag:

LocalDate i morgen = LocalDate.now (). PlusDays (1);

Dette eksempel får den aktuelle dato og fratrækker en måned. Bemærk, hvordan det accepterer en enum som tidsenheden:

LocalDate previousMonthSameDay = LocalDate.now (). Minus (1, ChronoUnit.MONTHS);

I de følgende to kodeeksempler analyserer vi datoen “2016-06-12” og får henholdsvis ugedag og dag i måneden. Bemærk returværdierne, den første er et objekt, der repræsenterer DayOfWeek mens den anden i en int der repræsenterer månedens ordinære værdi:

DayOfWeek søndag = LocalDate.parse ("2016-06-12"). GetDayOfWeek (); int tolv = LocalDate.parse ("2016-06-12"). getDayOfMonth ();

Vi kan teste, om en dato finder sted i et skudår. I dette eksempel tester vi, om den aktuelle dato er et skudår:

boolsk leapYear = LocalDate.now (). isLeapYear ();

Forholdet mellem en dato og en anden kan bestemmes at forekomme før eller efter en anden dato:

boolean notBefore = LocalDate.parse ("2016-06-12") .isBefore (LocalDate.parse ("2016-06-11")); boolsk isAfter = LocalDate.parse ("2016-06-12") .isAfter (LocalDate.parse ("2016-06-11"));

Datagrænser kan fås fra en given dato. I de følgende to eksempler får vi LocalDateTime der repræsenterer begyndelsen af ​​dagen (2016-06-12T00: 00) for den givne dato og LocalDate der repræsenterer henholdsvis begyndelsen af ​​måneden (2016-06-01):

LocalDateTime begyndelseOfDay = LocalDate.parse ("2016-06-12"). AtStartOfDay (); LocalDate firstDayOfMonth = LocalDate.parse ("2016-06-12"). Med (TemporalAdjusters.firstDayOfMonth ());

Lad os nu se på, hvordan vi arbejder med lokal tid.

3.2. Arbejder med Lokal tid

Det Lokal tid repræsenterer tid uden dato.

Svarende til LocalDate en forekomst af Lokal tid kan oprettes fra systemuret eller ved hjælp af "parse" og "of" -metoden. Se hurtigt på nogle af de almindeligt anvendte API'er nedenfor.

En forekomst af strøm Lokal tid kan oprettes fra systemuret som nedenfor:

LocalTime nu = LocalTime.now ();

I nedenstående kodeeksempel, vi skaber en Lokal tid repræsenterer 06:30 ved at analysere en strengrepræsentation:

LocalTime sixThirty = LocalTime.parse ("06:30");

Fabriksmetoden “af” kan bruges til at oprette en Lokal tid. For eksempel opretter nedenstående kode Lokal tid repræsenterer 06:30 ved hjælp af fabriksmetoden:

LocalTime sixThirty = LocalTime.of (6, 30);

Nedenstående eksempel opretter en Lokal tid ved at analysere en streng og tilføje en time til den ved hjælp af "plus" API. Resultatet ville være Lokal tid repræsenterer 07:30:

LocalTime sevenThirty = LocalTime.parse ("06:30"). Plus (1, ChronoUnit.HOURS);

Forskellige getter-metoder er tilgængelige, som kan bruges til at få specifikke tidsenheder som time, min og sekunder som nedenfor:

int seks = LocalTime.parse ("06:30"). getHour ();

Vi kan også kontrollere, om et bestemt tidspunkt er før eller efter et andet specifikt tidspunkt. Nedenstående kodeeksempel sammenligner to Lokal tid for hvilket resultatet ville være sandt:

boolean isbefore = LocalTime.parse ("06:30"). isBefore (LocalTime.parse ("07:30"));

Maks., Min. Og middagstid på en dag kan opnås med konstanter i Lokal tid klasse. Dette er meget nyttigt, når du udfører databaseforespørgsler for at finde poster inden for et givet tidsrum. For eksempel repræsenterer nedenstående kode 23: 59: 59.99:

LocalTime maxTime = LocalTime.MAX

Lad os nu dykke ned i LocalDateTime.

3.3. Arbejder med LocalDateTime

Det LocalDateTime bruges til at repræsentere en kombination af dato og klokkeslæt.

Dette er den mest anvendte klasse, når vi har brug for en kombination af dato og klokkeslæt. Klassen tilbyder en række API'er, og vi vil se på nogle af de mest anvendte.

En forekomst af LocalDateTime kan fås fra systemuret svarende til LocalDate og Lokal tid:

LocalDateTime.now ();

Nedenstående kodeeksempler forklarer, hvordan man opretter en forekomst ved hjælp af "of" og "parse" -metoderne fra fabrikken. Resultatet ville være et LocalDateTime instans, der repræsenterer 20. februar 2015, 06:30:

LocalDateTime.of (2015, måned. FEBRUAR, 20, 06, 30);
LocalDateTime.parse ("2015-02-20T06: 30: 00");

Der er API'er til hjælpeprogrammer, der understøtter tilføjelse og subtraktion af bestemte tidsenheder som dage, måneder, år og minutter er tilgængelige. Nedenstående kodeeksempler viser brugen af ​​“plus” og “minus” metoder. Disse API'er opfører sig nøjagtigt som deres kolleger i LocalDate og Lokal tid:

localDateTime.plusDays (1);
localDateTime.minusHours (2);

Getter-metoder er tilgængelige for at udtrække specifikke enheder svarende til dato og tidsklasser. I betragtning af ovenstående forekomst af LocalDateTime, nedenstående kodeeksempel returnerer februar måned:

localDateTime.getMonth ();

4. Brug ZonedDateTime API

Java 8 leverer ZonedDateTime når vi har brug for tidsspecifik dato og klokkeslæt. Det ZoneId er en identifikator, der bruges til at repræsentere forskellige zoner. Der er omkring 40 forskellige tidszoner og ZoneId bruges til at repræsentere dem som følger.

I dette kodestykke opretter vi en Zone til Paris:

ZoneId zoneId = ZoneId.of ("Europa / Paris"); 

Et sæt af alle zone-id'er kan opnås som nedenfor:

Indstil allZoneIds = ZoneId.getAvailableZoneIds ();

Det LocalDateTime kan konverteres til en bestemt zone:

ZonedDateTime zonedDateTime = ZonedDateTime.of (localDateTime, zoneId);

Det ZonedDateTime giver parse metode til at få tidszonespecifik dato:

ZonedDateTime.parse ("2015-05-03T10: 15: 30 + 01: 00 [Europe / Paris]");

En anden måde at arbejde med tidszonen er ved hjælp af OffsetDateTime. Det OffsetDateTime er en uforanderlig gengivelse af et dato-tidspunkt med en forskydning. Denne klasse gemmer alle dato- og tidsfelter med en nøjagtighed på nanosekunder samt forskydningen fra UTC / Greenwich.

Det OffSetDateTime instans kan oprettes som nedenfor ved hjælp af ZoneOffset. Her opretter vi en LocalDateTime repræsenterer kl. 20.30 den 20. februar 2015:

LocalDateTime localDateTime = LocalDateTime.of (2015, måned. FEBRUAR, 20, 06, 30);

Derefter tilføjer vi to timer til tiden ved at oprette en ZoneOffset og indstilling til localDateTime eksempel:

ZoneOffset offset = ZoneOffset.of ("+ 02:00"); OffsetDateTime offSetByTwo = OffsetDateTime .of (localDateTime, offset);

Vi har nu en localDateTime af 2015-02-20 06:30 +02: 00. Lad os nu gå videre til, hvordan du ændrer dato- og tidsværdier ved hjælp af Periode og Varighed klasser.

5. Brug Periode og Varighed

Det Periode klasse repræsenterer en mængde tid udtrykt i år, måneder og dage og Varighed klasse repræsenterer en mængde tid udtrykt i sekunder og nano sekunder.

5.1. Arbejder med Periode

Det Periode klasse bruges i vid udstrækning til at ændre værdier for en given dato eller for at opnå forskellen mellem to datoer:

LocalDate initialDate = LocalDate.parse ("10.05.2007");

Det Dato kan manipuleres ved hjælp af Periode som vist i følgende kodestykke:

LocalDate finalDate = initialDate.plus (Period.ofDays (5));

Det Periode klassen har forskellige getter metoder såsom getYears, getMonths og getDays for at få værdier fra en Periode objekt. Nedenstående kodeeksempel returnerer en int værdi på 5, når vi prøver at få forskel i form af dage:

int fem = Period.between (initialDate, finalDate) .getDays ();

Det Periode mellem to datoer kan fås i en bestemt enhed såsom dage eller måned eller år ved hjælp af ChronoUnit.between:

lang fem = ChronoUnit.DAYS.between (initialDate, finalDate);

Dette kodeeksempel returnerer fem dage. Lad os fortsætte med at kigge på Varighed klasse.

5.2. Arbejder med Varighed

Svarende til Periode, det Varighedsklasse er brug for at håndtere Tid. I den følgende kode opretter vi en Lokal tid 6:30 og tilføj derefter en varighed på 30 sekunder for at lave en Lokal tid 06:30:30:

LocalTime initialTime = LocalTime.of (6, 30, 0); LocalTime finalTime = initialTime.plus (Duration.ofSeconds (30));

Det Varighed mellem to øjeblikke kan opnås enten som en Varighed eller som en bestemt enhed. I det første kodestykke bruger vi mellem() metode til Varighed klasse for at finde tidsforskellen mellem finalTime og initialTime og returner forskellen i sekunder:

lang tredive = Duration.between (initialTime, finalTime) .getSeconds ();

I det andet eksempel bruger vi mellem() metode til ChronoUnit klasse til at udføre den samme operation:

lang tredive = ChronoUnit.SECONDS.between (initialTime, finalTime);

Nu vil vi se på, hvordan man konverterer eksisterende Dato og Kalender til nyt Dato/Tid.

6. Kompatibilitet med Dato og Kalender

Java 8 har tilføjet toInstant () metode, der hjælper med at konvertere eksisterende Dato og Kalender forekomst til nyt Date Time API som i følgende kodestykke:

LocalDateTime.ofInstant (date.toInstant (), ZoneId.systemDefault ()); LocalDateTime.ofInstant (kalender.toInstant (), ZoneId.systemDefault ());

Det LocalDateTime kan konstrueres fra epoke sekunder som nedenfor. Resultatet af nedenstående kode ville være et LocalDateTime repræsenterer 2016-06-13T11: 34: 50:

LocalDateTime.ofEpochSecond (1465817690, 0, ZoneOffset.UTC);

Lad os nu gå videre til Dato og Tid formatering.

7. Dato og Tid Formatering

Java 8 leverer API'er til nem formatering af Dato og Tid:

LocalDateTime localDateTime = LocalDateTime.of (2015, måned. JANUAR, 25, 6, 30);

Koden nedenfor passerer et ISO-datoformat for at formatere den lokale dato. Resultatet ville være 2015-01-25:

String localDateString = localDateTime.format (DateTimeFormatter.ISO_DATE);

Det DateTimeFormatter giver forskellige standardformateringsmuligheder. Brugerdefinerede mønstre kan også leveres til formateringsmetoden, som nedenfor, som ville returnere LocalDate som 2015/01/25:

localDateTime.format (DateTimeFormatter.ofPattern ("åååå / MM / dd"));

Vi kan passere i formateringsstil enten som KORT, LANG eller MEDIUM som en del af formateringsindstillingen. Nedenstående kodeeksempel vil give et output, der repræsenterer LocalDateTime i 25.-jan-2015, 06:30:00:

localDateTime .format (DateTimeFormatter.ofLocalizedDateTime (FormatStyle.MEDIUM)) .withLocale (Locale.UK);

Lad os se på alternativer, der er tilgængelige til Java 8 Core Dato/Tid API'er.

8. Backport og alternative muligheder

8.1. Brug af Project Threeten

For organisationer, der er på vej til at flytte til Java 8 fra Java 7 eller Java 6 og ønsker at bruge dato og klokkeslæt API, giver projektet threenen mulighed for backport. Udviklere kan bruge klasser, der er tilgængelige i dette projekt for at opnå den samme funktionalitet som den nye Java 8 Dato og Tid API, og når de flytter til Java 8, kan pakkerne skiftes. Artefakt til projektet tre kan findes i Maven Central Repository:

 org.threeten threetenbp 1.3.1 

8.2. Joda-Time Bibliotek

Et andet alternativ til Java 8 Dato og Tid bibliotek er Joda-Time bibliotek. Faktisk Java 8 Dato tid API'er er blevet ledet i fællesskab af forfatteren af ​​Joda-Time-biblioteket (Stephen Colebourne) og Oracle. Dette bibliotek giver stort set alle funktioner, der understøttes i Java 8 Dato tid projekt. Artefakten kan findes i maven central ved at inkludere nedenstående pom afhængighed i dit projekt:

 joda-tid joda-tid 2.9.4 

9. Konklusion

Java 8 leverer et rigt sæt API'er med ensartet API-design for lettere udvikling.

Kodeprøverne til ovenstående artikel findes i Java 8 Date / Time git repository.