Uvod u Joda-Time

1. Uvod

Joda-Time je najčešće korištena knjižnica za obradu datuma i vremena prije izlaska Jave 8. Njegova je svrha bila ponuditi intuitivni API za obradu datuma i vremena, a također riješiti probleme s dizajnom koji su postojali u Java Date / Time API.

Središnji koncepti implementirani u ovoj knjižnici predstavljeni su u JDK jezgri izdavanjem verzije Java 8. Novi API za datum i vrijeme nalazi se u java.vrijeme paket (JSR-310). Pregled ovih značajki možete pronaći u ovom članku.

Nakon izlaska Java 8, autori smatraju da je projekt uglavnom gotov i savjetuju upotrebu Java 8 API-a ako je moguće.

2. Zašto koristiti Joda-Time?

Datum / vrijeme API-ja, prije Jave 8, predstavljao je višestruke probleme s dizajnom.

Među problemima je činjenica da Datum i SimpleDateFormatter klase nisu zaštićene od niti. Da biste riješili ovaj problem, Joda-Time koristi nepromjenjive klase za rukovanje datumom i vremenom.

The Datum klasa ne predstavlja stvarni datum, već umjesto toga, određuje trenutak u vremenu, s milisekundnom preciznošću. Godina u Datum započinje od 1900. godine, dok većina operacija s datumima obično koristi vrijeme epohe koje počinje od 1. siječnja 1970.

Također, pomak dana, mjeseca i godine Datum je kontraintuitivan. Dani počinju od 0, dok mjesec počinje od 1. Da bismo pristupili bilo kojem od njih, moramo koristiti Kalendar razred. Joda-Time nudi čist i tečan API za rukovanje datumima i vremenom.

Joda-Time također nudi podrška za osam kalendarskih sustava, dok Java nudi samo 2: gregorijanski - java.util.GregorianCalendar i japanski - java.util.JapaneseImperialCalendar.

3. Postavljanje

Da bismo uključili funkcionalnost Joda-Time biblioteke, moramo dodati sljedeću ovisnost iz Maven Central:

 joda-vrijeme joda-vrijeme 2.10 

4. Pregled knjižnice

Joda-Time modelira koncept datuma i vremena koristeći nastavu u org.joda.vrijeme paket.

Među tim razredima najčešće se koriste:

  • LocalDate - predstavlja datum bez vremena
  • Lokalno vrijeme - predstavlja vrijeme bez vremenske zone
  • LocalDateTime - predstavlja i datum i vrijeme bez vremenske zone
  • Trenutak - predstavlja točnu vremensku točku u milisekundama iz doba Jave 1970-01-01T00: 00: 00Z
  • Trajanje - predstavlja trajanje u milisekundama između 2 točke u vremenu
  • Razdoblje - slično Trajanje, ali dopuštajući pristup pojedinim komponentama objekta datuma i vremena, poput godina, mjeseca, dana itd.
  • Interval - predstavlja vremenski interval između 2 trenutka

Ostale važne značajke su analizatori datuma i oblikovači. Oni se mogu naći u org.joda.time.format paket.

The kalendarski sustav i vremensku zonu određene klase mogu se naći u org.joda.time.chrono i org.joda.time.tz paketi.

Pogledajmo neke primjere u kojima koristimo ključne značajke Joda-Timea za upravljanje datumom i vremenom.

5. Predstavljanje datuma i vremena

5.1. Trenutni datum i vrijeme

Trenutni datum, bez podataka o vremenu, može se dobiti pomoću sada() metoda iz the LocalDate razred:

LocalDate currentDate = LocalDate.now ();

Kad nam treba samo trenutno vrijeme, bez podataka o datumu, možemo koristiti Lokalno vrijeme razred:

LocalTime currentTime = LocalTime.now ();

Da biste dobili a prikaz trenutnog datuma i vremena bez razmatranja vremenske zone, možemo koristiti LocalDateTime:

LocalDateTime currentDateAndTime = LocalDateTime.now ();

Sada, koristeći currentDateAndTime, možemo ga pretvoriti u druge vrste objekata koji modeliraju datum i vrijeme.

Možemo dobiti a Datum vrijeme objekt (koji uzima u obzir vremensku zonu) pomoću metode toDateTime (). Kad vrijeme nije potrebno, možemo ga pretvoriti u LocalDate s metodom toLocalDate (), i kada nam treba samo vrijeme koje možemo iskoristiti toLocalTime () dobiti a Lokalno vrijeme objekt:

DateTime dateTime = currentDateAndTime.toDateTime (); LocalDate localDate = currentDateAndTime.toLocalDate (); LocalTime localTime = currentDateAndTime.toLocalTime ();

Sve gore navedene metode imaju preopterećenu metodu koja prihvaća a DateTimeZone objekt koji će nam pomoći da predstavimo datum ili vrijeme u navedenoj vremenskoj zoni:

LocalDate currentDate = LocalDate.now (DateTimeZone.forID ("America / Chicago"));

Također, Joda-Time nudi izvrsnu integraciju s Java datumom i vremenom API. Konstruktori prihvaćaju a java.util.Datum objekt, a također možemo koristiti i toDate () metoda za vraćanje a java.util.Datum objekt:

LocalDateTime currentDateTimeFromJavaDate = novo LocalDateTime (novi datum ()); Datum currentJavaDate = currentDateTimeFromJavaDate.toDate ();

5.2. Prilagođeni datum i vrijeme

Kako bi prikazao prilagođeni datum i vrijeme, Joda-Time nam nudi nekoliko konstruktora. Možemo odrediti sljedeće objekte:

  • an Trenutak
  • Java Datum objekt
  • a Niz prikaz datuma i vremena pomoću ISO formata
  • dijelovi datuma i vremena: godina, mjesec, dan, sat, minuta, sekunda, milisekunda
Datum oneMinuteAgoDate = novi datum (System.currentTimeMillis () - (60 * 1000)); Instant oneMinutesAgoInstant = novi Instant (oneMinuteAgoDate); DateTime customDateTimeFromInstant = novo DateTime (oneMinutesAgoInstant); DateTime customDateTimeFromJavaDate = novo DateTime (oneMinuteAgoDate); DateTime customDateTimeFromString = novo DateTime ("2018-05-05T10: 11: 12.123"); DateTime customDateTimeFromParts = novi DateTime (2018, 5, 5, 10, 11, 12, 123); 

Drugi način na koji možemo definirati prilagođeni datum i vrijeme je raščlanjivanjem zadanog Niz prikaz datuma i vremena u ISO formatu:

DateTime parsedDateTime = DateTime.parse ("2018-05-05T10: 11: 12.123");

Također možemo raščlaniti prilagođene prikaze datuma i vremena definirajući običaj DateTimeFormatter:

DateTimeFormatter dateTimeFormatter = DateTimeFormat.forPattern ("MM / dd / yyyy HH: mm: ss"); DateTime parsedDateTimeUsingFormatter = DateTime.parse ("05/05/2018 10:11:12", dateTimeFormatter);

6. Rad s datumom i vremenom

6.1. Koristeći Trenutak

An Trenutak predstavlja broj milisekundi od 1970-01-01T00: 00: 00Z do određenog trenutka u vremenu. Na primjer, trenutni trenutak u vremenu može se dobiti pomoću zadanog konstruktora ili metode sada():

Instant instant = novo Instant (); Instant.now ();

Da biste stvorili Trenutak za prilagođeni trenutak u vremenu možemo koristiti bilo koji od konstruktora ili metode ofEpochMilli () i ofEpochSecond ():

Instant instantFromEpochMilli = Instant.ofEpochMilli (milliesFromEpochTime); Instant instantFromEpocSeconds = Instant.ofEpochSecond (secondsFromEpochTime);

Konstruktori prihvaćaju a Niz predstavlja datum i vrijeme u ISO formatu, Java Datum ili a dugo vrijednost koja predstavlja broj milisekundi od 1970-01-01T00: 00: 00Z:

Instant instantFromString = novo Instant ("2018-05-05T10: 11: 12"); Instant instantFromDate = novi Instant (oneMinuteAgoDate); Instant instantFromTimestamp = novo Instant (System.currentTimeMillis () - (60 * 1000));

Kada su datum i vrijeme predstavljeni kao Niz imamo mogućnost raščlaniti Niz koristeći naš željeni format:

Instant parsedInstant = Instant.parse ("05/05/2018 10:11:12", dateTimeFormatter);

Sad kad znamo što Trenutak predstavlja i kako ga možemo stvoriti, pogledajmo kako se može koristiti.

Za usporedbu s Trenutak predmeti koje možemo koristiti compareTo () jer provodi Usporedive sučelje, ali također možemo koristiti Joda-Time API metode dane u ReadableInstant sučelje koje Trenutak također provodi:

assertTrue (instantNow.compareTo (oneMinuteAgoInstant)> 0); assertTrue (instantNow.isAfter (oneMinuteAgoInstant)); assertTrue (oneMinuteAgoInstant.isBefore (instantNow)); assertTrue (oneMinuteAgoInstant.isBeforeNow ()); assertFalse (oneMinuteAgoInstant.isEqual (instantNow));

Još jedna korisna značajka je ta Trenutak može se pretvoriti u Datum vrijeme objekt ili događaj Java Datum:

DateTime dateTimeFromInstant = instant.toDateTime (); Datum javaDateFromInstant = instant.toDate ();

Kada trebamo pristupiti dijelovima datuma i vremena, poput godine, sata i tako dalje, možemo koristiti dobiti() metodu i navedite a DateTimeField:

int year = instant.get (DateTimeFieldType.year ()); int month = instant.get (DateTimeFieldType.monthOfYear ()); int day = instant.get (DateTimeFieldType.dayOfMonth ()); int sat = instant.get (DateTimeFieldType.hourOfDay ());

Sad kad smo pokrili Trenutak razredu pogledajmo nekoliko primjera kako se možemo koristiti Trajanje, Razdoblje i Interval.

6.2. Koristeći Trajanje, Razdoblje i Interval

A Trajanje predstavlja vrijeme u milisekundama između dviju vremenskih točaka ili u ovom slučaju može biti dvije Trenutci. To ćemo upotrijebiti kada trebamo dodati ili oduzeti određeno vrijeme drugom ili od drugog Trenutak bez razmatranja kronologije i vremenskih zona:

long currentTimestamp = System.currentTimeMillis (); dugačak oneHourAgo = trenutna vremenska oznaka - 24 * 60 * 1000; Trajanje trajanja = novo trajanje (oneHourAgo, currentTimestamp); Instant.now (). Plus (trajanje);

Također, možemo odrediti koliko dana, sati, minuta, sekundi ili milisekundi predstavlja trajanje:

long durationInDays = duration.getStandardDays (); long durationInHours = duration.getStandardHours (); long durationInMinutes = duration.getStandardMinutes (); long durationInSeconds = duration.getStandardSeconds (); dugo trajanjeInMilli = trajanje.getMillis ();

Glavna razlika između Razdoblje i Trajanje je li to Razdoblje definiran je u smislu njegovih komponenata datuma i vremena (godine, mjeseci, sati itd.) i ne predstavlja točan broj milisekundi. Prilikom korištenja Razdoblje izračuni datuma i vremena razmotrit će vremensku zonu i ljetno računanje vremena.

Na primjer, dodavanjem a Razdoblje od 1 mjeseca do 1. veljače rezultirat će datumskim predstavljanjem 1. ožujka. Pomoću Razdoblje knjižnica će uzeti u obzir prijestupne godine.

Ako ćemo koristiti a Trajanje mi rezultat ne bi bio točan, jer Trajanje predstavlja fiksnu količinu vremena koja ne uzima u obzir kronologiju ili vremenske zone:

Razdoblje razdoblja = novo Razdoblje (). WithMonths (1); LocalDateTime datePlusPeriod = localDateTime.plus (period);

An Interval, kako naziv govori, predstavlja datum i vremenski interval između dvije fiksne točke u vremenu predstavljene s dvije Trenutak objekti:

Intervalni interval = novi Interval (oneMinuteAgoInstant, instantNow);

Razred je koristan kada moramo provjeriti preklapaju li se dva intervala ili izračunati jaz između njih. The preklapanje() metoda će vratiti preklapanje Interval ili null kada se ne preklapaju:

Instant startInterval1 = novi Instant ("2018-05-05T09: 00: 00.000"); Instant endInterval1 = novi Instant ("2018-05-05T11: 00: 00.000"); Interval interval1 = novi Interval (startInterval1, endInterval1); Instant startInterval2 = novo Instant ("2018-05-05T10: 00: 00.000"); Instant endInterval2 = novo Instant ("2018-05-05T11: 00: 00.000"); Interval interval2 = novi Interval (startInterval2, endInterval2); Preklapanje intervalaInterval = interval1.preklapanje (interval2);

Razlika između intervala može se izračunati pomoću jaz () metodu, a kada želimo znati je li kraj intervala jednak početku drugog intervala, možemo koristiti naslonjen () metoda:

assertTrue (interval1.abuts (novi Interval (novi Instant ("2018-05-05T11: 00: 00.000"), novi Instant ("2018-05-05T13: 00: 00.000")))));

6.3. Datum i vrijeme

Neke od najčešćih operacija su zbrajanje, oduzimanje i pretvaranje datuma i vremena. Knjižnica pruža specifične metode za svaki razred LocalDate, Lokalno vrijeme, LocalDateTime, i Datum vrijeme. Važno je napomenuti da su ove klase nepromjenjive, tako da će svaki poziv metode stvoriti novi objekt svog tipa.

Idemo uzeti LocalDateTime za trenutni trenutak i pokušajte promijeniti njegovu vrijednost:

LocalDateTime currentLocalDateTime = LocalDateTime.now ();

Da biste dodali dodatni dan currentLocalDateTime koristimo plusDays () metoda:

LocalDateTime nextDayDateTime = currentLocalDateTime.plusDays (1);

Možemo i koristiti plus() metoda za dodavanje a Razdoblje ili Trajanje našem currentLocalDateTime:

Period oneMonth = novo Period (). WithMonths (1); LocalDateTime nextMonthDateTime = currentLocalDateTime.plus (oneMonth);

Metode su slične za ostale komponente datuma i vremena, na primjer, plusGodine () za dodavanje dodatnih godina, plusSeconds () za dodavanje dodatnih sekundi i tako dalje.

Da oduzmemo dan od našeg currentLocalDateTime možemo koristiti minusDays () metoda:

LocalDateTime previousDayLocalDateTime = currentLocalDateTime.minusDays (1);

Osim toga, radeći izračune s datumom i vremenom, možemo i postaviti pojedinačne dijelove datuma ili vremena. Na primjer, podešavanje sata na 10 može se postići pomoću withHourOfDay () metoda. Ostale metode koje počinju s prefiksom "s" može se koristiti za postavljanje komponenata tog datuma ili vremena:

LocalDateTime currentDateAtHour10 = currentLocalDateTime .withHourOfDay (0) .withMinuteOfHour (0) .withSecondOfMinute (0) .withMillisOfSecond (0);

Sljedeći važan aspekt je taj da možemo pretvoriti iz vrste datuma i vremena u drugu. Da bismo to učinili, možemo se služiti određenim metodama koje nudi knjižnica:

  • toDateTime () - obraća LocalDateTime do a Datum vrijeme objekt
  • toLocalDate () - obraća LocalDateTime do a LocalDate objekt
  • toLocalTime () - pretvara LocalDateTime u LocalTime objekt
  • toDate () - obraća LocalDateTime na Javu Datum objekt

7. Rad s vremenskim zonama

Joda-Time olakšava nam rad s različitim vremenskim zonama i promjenama između njih. Mi imamo DateTimeZone apstraktna klasa koja se koristi za predstavljanje svih aspekata vremenske zone.

Zadana vremenska zona koju koristi Joda-Time odabire se iz korisnik.vremenska zona Svojstvo Java sustava. API knjižnice omogućuje nam da za svaku klasu ili izračun pojedinačno odredimo koju vremensku zonu treba koristiti. Na primjer, možemo stvoriti objekt LocalDateTime

Kad znamo da ćemo koristiti cijelu vremensku zonu u cijeloj aplikaciji, možemo postaviti zadanu vremensku zonu:

DateTimeZone.setDefault (DateTimeZone.UTC);

Od sada će sve operacije datuma i vremena, ako nije drugačije određeno, biti predstavljene u UTC vremenskoj zoni.

Da bismo vidjeli sve dostupne vremenske zone, možemo se poslužiti metodom getAvailableIDs ():

DateTimeZone.getAvailableIDs ()

Kada trebamo predstaviti datum ili vrijeme u određenoj vremenskoj zoni, možemo koristiti bilo koju klasu Lokalno vrijeme, LocalDate, LocalDateTime, Datum vrijeme i navedite u konstruktoru DateTimeZone objekt:

DateTime dateTimeInChicago = novo DateTime (DateTimeZone.forID ("America / Chicago")); DateTime dateTimeInBucharest = novi DateTime (DateTimeZone.forID ("Europa / Bukurešt")); LocalDateTime localDateTimeInChicago = novo LocalDateTime (DateTimeZone.forID ("Amerika / Chicago"));

Također, prilikom konverzije između tih klasa možemo odrediti željenu vremensku zonu. Metoda toDateTime () prihvaća a DateTimeZone objekt i toDate () prihvaća objekt java.util.TimeZone:

DateTime convertDateTime = localDateTimeInChicago.toDateTime (DateTimeZone.forID ("Europa / Bukurešt")); Datum pretvorenDate = localDateTimeInChicago.toDate (TimeZone.getTimeZone ("Europa / Bukurešt"));

8. Zaključak

Joda-Time je fantastična knjižnica koja je započela s glavnim ciljem da riješi probleme u JDK u vezi s datumom i vremenom. Ubrzo je postao zapravo knjižnica za rukovanje datumom i vremenom, a nedavno su glavni pojmovi iz nje predstavljeni u Javi 8.

Važno je napomenuti da autor to smatra "Biti uglavnom gotov projekt" i preporučuje migraciju postojećeg koda kako bi se koristila implementacija Java 8.

Izvorni kôd članka dostupan je na GitHubu.