Inleiding tot Joda-Time

1. Inleiding

Joda-Time is de meest gebruikte bibliotheek voor het verwerken van datum en tijd, vóór de release van Java 8. Het doel was om een ​​intuïtieve API aan te bieden voor het verwerken van datum en tijd en ook om de ontwerpproblemen aan te pakken die bestonden in de Java Date / Time API.

De centrale concepten die in deze bibliotheek zijn geïmplementeerd, zijn geïntroduceerd in de JDK-kern met de release van de Java 8-versie. De nieuwe datum- en tijd-API is te vinden in het java.time pakket (JSR-310). Een overzicht van deze features vind je in dit artikel.

Na de release van Java 8 beschouwen auteurs het project als grotendeels voltooid en adviseren ze om indien mogelijk de Java 8 API te gebruiken.

2. Waarom Joda-Time gebruiken?

De datum / tijd-API, vóór Java 8, leverde meerdere ontwerpproblemen op.

Een van de problemen is het feit dat de Datum en SimpleDateFormatter klassen zijn niet thread-safe. Om dit probleem aan te pakken, Joda-Time gebruikt onveranderlijke klassen voor het afhandelen van datum en tijd.

De Datum klasse vertegenwoordigt geen werkelijke datum, maar in plaats daarvan specificeert het een moment in de tijd, met een precisie van milliseconden. Het jaar in a Datum begint vanaf 1900, terwijl de meeste datumbewerkingen gewoonlijk Epoch-tijd gebruiken die begint op 1 januari 1970.

Ook de dag-, maand- en jaarverschuiving van a Datum is contra-intuïtief. Dagen beginnen bij 0, terwijl de maand begint bij 1. Om toegang te krijgen tot een van hen, moeten we de Kalender klasse. Joda-Time biedt een schone en vloeiende API voor het omgaan met datums en tijden.

Joda-Time biedt ook ondersteuning voor acht kalendersystemen, terwijl Java er slechts 2 biedt: Gregoriaans - java.util.GregorianCalendar en Japans - java.util.JapaneseImperialCalendar.

3. Installatie

Om de functionaliteit van de Joda-Time-bibliotheek op te nemen, moeten we de volgende afhankelijkheid van Maven Central toevoegen:

 joda-tijd joda-tijd 2.10 

4. Bibliotheekoverzicht

Joda-Time modelleert de concept van datum en tijd met behulp van de klassen in de org.joda.time pakket.

De meest gebruikte klassen zijn:

  • LocalDate - staat voor een datum zonder tijd
  • Lokale tijd - staat voor de tijd zonder de tijdzone
  • LocalDateTime - vertegenwoordigt zowel de datum als de tijd zonder tijdzone
  • Onmiddellijk - vertegenwoordigt een exact tijdstip in milliseconden vanaf het Java-tijdperk van 1970-01-01T00: 00: 00Z
  • Looptijd - staat voor de duur in milliseconden tussen 2 punten in de tijd
  • Periode - gelijkwaardig aan Looptijd, maar geeft toegang tot individuele componenten van het datum- en tijdobject, zoals jaren, maand, dagen, enz.
  • Interval - staat voor het tijdsinterval tussen 2 momenten

Andere belangrijke kenmerken zijn de date parsers en formatters. Deze zijn te vinden in het org.joda.time.format pakket.

De kalendersysteem en tijdzone specifieke klassen zijn te vinden in het org.joda.time.chrono en org.joda.time.tz pakketjes.

Laten we eens kijken naar enkele voorbeelden waarin we de belangrijkste functies van Joda-Time gebruiken om met datum en tijd om te gaan.

5. Vertegenwoordigen datum en tijd

5.1. Huidige datum en tijd

De huidige datum, zonder tijdinformatie, kan worden verkregen met behulp van de nu() methode van de LocalDate klasse:

LocalDate currentDate = LocalDate.now ();

Als we alleen de huidige tijd nodig hebben, zonder datuminformatie, kunnen we de Lokale tijd klasse:

LocalTime currentTime = LocalTime.now ();

Om een weergave van de huidige datum en tijd zonder rekening te houden met de tijdzone, kunnen we gebruiken LocalDateTime:

LocalDateTime currentDateAndTime = LocalDateTime.now ();

Nu met behulp van currentDateAndTime, kunnen we het converteren naar de andere soorten objecten die de datum en tijd modelleren.

We kunnen een Datum Tijd object (dat rekening houdt met de tijdzone) door de methode te gebruiken toDateTime (). Als tijd niet nodig is, kunnen we deze omzetten in een LocalDate met de methode toLocalDate (), en als we alleen de tijd nodig hebben die we kunnen gebruiken toLocalTime () om een Lokale tijd voorwerp:

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

Alle bovenstaande methoden hebben een overbelaste methode die een DateTimeZone voorwerp om ons te helpen de datum of tijd in de opgegeven tijdzone weer te geven:

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

Bovendien biedt Joda-Time uitstekende integratie met de Java Date and Time API. De constructeurs accepteren een java.util.Date object en we kunnen ook de daten() methode om een java.util.Date voorwerp:

LocalDateTime currentDateTimeFromJavaDate = nieuwe LocalDateTime (nieuwe datum ()); Datum currentJavaDate = currentDateTimeFromJavaDate.toDate ();

5.2. Aangepaste datum en tijd

Om aangepaste datum en tijd weer te geven, stelt Joda-Time ons verschillende constructeurs ter beschikking. We kunnen de volgende objecten specificeren:

  • een Onmiddellijk
  • een Java Datum voorwerp
  • een Draad weergave van de datum en tijd met behulp van het ISO-formaat
  • delen van de datum en tijd: jaar, maand, dag, uur, minuut, seconde, milliseconde
Datum oneMinuteAgoDate = nieuwe datum (System.currentTimeMillis () - (60 * 1000)); Instant oneMinutesAgoInstant = nieuwe Instant (oneMinuteAgoDate); DateTime customDateTimeFromInstant = nieuwe DateTime (oneMinutesAgoInstant); DateTime customDateTimeFromJavaDate = nieuwe DateTime (oneMinuteAgoDate); DateTime customDateTimeFromString = nieuwe DateTime ("2018-05-05T10: 11: 12.123"); DateTime customDateTimeFromParts = nieuwe DateTime (2018, 5, 5, 10, 11, 12, 123); 

Een andere manier waarop we een aangepaste datum en tijd kunnen definiëren, is door een gegeven te ontleden Draad weergave van een datum en tijd in het ISO-formaat:

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

We kunnen ook aangepaste weergaven van een datum en tijd ontleden door een gewoonte te definiëren DateTimeFormatter:

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

6. Werken met datum en tijd

6.1. Gebruik makend van Onmiddellijk

Een Onmiddellijk staat voor het aantal milliseconden vanaf 1970-01-01T00: 00: 00Z tot een bepaald moment in de tijd. Het huidige moment in de tijd kan bijvoorbeeld worden verkregen met behulp van de standaardconstructor of de methode nu():

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

Om een Onmiddellijk voor een aangepast moment in de tijd kunnen we een van de constructors gebruiken of de methoden gebruiken van EpochMilli () en ofEpochSecond ():

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

De constructeurs accepteren een Draad vertegenwoordigt een datum en tijd in de ISO-indeling, een Java Datum of een lang waarde die het aantal milliseconden vertegenwoordigt vanaf 1970-01-01T00: 00: 00Z:

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

Wanneer datum en tijd worden weergegeven als een Draad we hebben de mogelijkheid om het Draad met behulp van ons gewenste formaat:

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

Nu we weten wat Onmiddellijk vertegenwoordigt en hoe we er een kunnen maken, laten we eens kijken hoe het kan worden gebruikt.

Om mee te vergelijken Onmiddellijk objecten die we kunnen gebruiken vergelijk met() omdat het de Vergelijkbaar interface, maar we kunnen ook de Joda-Time API-methoden gebruiken die in de ReadableInstant interface die Onmiddellijk implementeert ook:

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

Een andere handige functie is dat Onmiddellijk kan worden geconverteerd naar een Datum Tijd object of gebeurtenis een Java Datum:

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

Als we toegang moeten hebben tot delen van een datum en tijd, zoals het jaar, het uur enzovoort, kunnen we de krijgen() methode en specificeer een DateTimeField:

int jaar = instant.get (DateTimeFieldType.year ()); int maand = instant.get (DateTimeFieldType.monthOfYear ()); int dag = instant.get (DateTimeFieldType.dayOfMonth ()); int uur = instant.get (DateTimeFieldType.hourOfDay ());

Nu we de Onmiddellijk klasse laten we enkele voorbeelden bekijken van hoe we kunnen gebruiken Looptijd, Periode en Interval.

6.2. Gebruik makend van Looptijd, Periode en Interval

EEN Looptijd vertegenwoordigt de tijd in milliseconden tussen twee punten in de tijd of in dit geval zou het twee kunnen zijn Instants. We gebruiken dit wanneer we een bepaalde hoeveelheid tijd van of naar een andere moeten optellen of aftrekken Onmiddellijk zonder rekening te houden met chronologie en tijdzones:

lang currentTimestamp = System.currentTimeMillis (); lange oneHourAgo = currentTimestamp - 24 * 60 * 1000; Duur duur = nieuwe duur (oneHourAgo, currentTimestamp); Instant.now (). Plus (duur);

We kunnen ook bepalen hoeveel dagen, uren, minuten, seconden of milliseconden de duur vertegenwoordigt:

lange durationInDays = duration.getStandardDays (); lange durationInHours = duration.getStandardHours (); lange durationInMinutes = duration.getStandardMinutes (); lange durationInSeconds = duration.getStandardSeconds (); lange durationInMilli = duration.getMillis ();

Het belangrijkste verschil tussen Periode en Looptijd is dat Periode wordt gedefinieerd in termen van zijn datum- en tijdcomponenten (jaren, maanden, uren, enz.) en vertegenwoordigt niet een exact aantal milliseconden. Tijdens gebruik Periode datum- en tijdberekeningen houdt rekening met de tijdzone en zomertijd.

Voeg bijvoorbeeld een Periode van 1 maand tot 1 februari resulteert in de datumweergave van 1 maart. Door het gebruiken van Periode de bibliotheek houdt rekening met schrikkeljaren.

Als we een Looptijd we het resultaat zou niet correct zijn, omdat de Looptijd vertegenwoordigt een vaste hoeveelheid tijd die geen rekening houdt met chronologie of tijdzones:

Periode periode = nieuwe periode (). WithMonths (1); LocalDateTime datePlusPeriod = localDateTime.plus (punt);

Een Interval, zoals de naam aangeeft, vertegenwoordigt het datum- en tijdsinterval tussen twee vaste tijdstippen, vertegenwoordigd door twee Onmiddellijk voorwerpen:

Interval interval = nieuw interval (oneMinuteAgoInstant, instantNow);

De klasse is handig wanneer we moeten controleren of twee intervallen elkaar overlappen of wanneer we de afstand ertussen moeten berekenen. De overlappen() methode retourneert de overlapping Interval of nul wanneer ze elkaar niet overlappen:

Instant startInterval1 = nieuwe Instant ("2018-05-05T09: 00: 00.000"); Instant endInterval1 = nieuwe Instant ("2018-05-05T11: 00: 00.000"); Interval interval1 = nieuw interval (startInterval1, endInterval1); Instant startInterval2 = nieuwe Instant ("2018-05-05T10: 00: 00.000"); Instant endInterval2 = nieuwe Instant ("2018-05-05T11: 00: 00.000"); Interval interval2 = nieuw interval (startInterval2, endInterval2); Interval overlappingInterval = interval1.overlap (interval2);

Het verschil tussen intervallen kan worden berekend met de kloof() methode, en als we willen weten of het einde van een interval gelijk is aan het begin van een ander interval, kunnen we de grenst aan methode:

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

6.3. Datum- en tijdbewerkingen

Enkele van de meest voorkomende bewerkingen zijn het optellen, aftrekken en converteren van datum en tijd. De bibliotheek biedt specifieke methoden voor elk van de klassen LocalDate, Lokale tijd, LocalDateTime, en Datum Tijd. Het is belangrijk op te merken dat deze klassen onveranderlijk zijn, zodat elke methode-aanroep een nieuw object van zijn type zal creëren.

Laten we nemen LocalDateTime voor het huidige moment en probeer de waarde ervan te veranderen:

LocalDateTime currentLocalDateTime = LocalDateTime.now ();

Om een ​​extra dag aan toe te voegen currentLocalDateTime wij gebruiken de plusDays () methode:

LocalDateTime nextDayDateTime = currentLocalDateTime.plusDays (1);

We kunnen ook gebruik maken van plus() methode om een Periode of Looptijd naar onze currentLocalDateTime:

Periode oneMonth = nieuwe periode (). WithMonths (1); LocalDateTime nextMonthDateTime = currentLocalDateTime.plus (oneMonth);

De methoden zijn vergelijkbaar voor de andere datum- en tijdcomponenten, bijvoorbeeld plusJaren () voor het toevoegen van extra jaren, plusSeconds () voor het toevoegen van meer seconden enzovoort.

Om een ​​dag af te trekken van onze currentLocalDateTime we kunnen de minusDays () methode:

LocalDateTime previousDayLocalDateTime = currentLocalDateTime.minusDays (1);

Naast berekeningen met datum en tijd kunnen we ook afzonderlijke delen van de datum of tijd instellen. U kunt bijvoorbeeld het uur instellen op 10 met de metHourOfDay () methode. Andere methoden die beginnen met het voorvoegsel "met" kan worden gebruikt om componenten van die datum of tijd in te stellen:

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

Een ander belangrijk aspect is dat we kunnen converteren van een datum- en tijdklassetype naar een ander. Om dit te doen, kunnen we specifieke methoden gebruiken die door de bibliotheek worden aangeboden:

  • toDateTime () - bekeert LocalDateTime naar een Datum Tijd voorwerp
  • toLocalDate () - bekeert LocalDateTime naar een LocalDate voorwerp
  • toLocalTime () - converteert LocalDateTime naar een LocalTime-object
  • daten() - bekeert LocalDateTime naar een Java Datum voorwerp

7. Werken met tijdzones

Joda-Time maakt het voor ons gemakkelijk om met verschillende tijdzones te werken en daartussen te wisselen. We hebben de DateTimeZone abstracte klasse die wordt gebruikt om alle aspecten met betrekking tot een tijdzone weer te geven.

De standaardtijdzone die door Joda-Time wordt gebruikt, wordt geselecteerd uit de user.timezone Java-systeemeigenschap. Met de bibliotheek-API kunnen we voor elke klasse of berekening afzonderlijk specificeren welke tijdzone moet worden gebruikt. We kunnen bijvoorbeeld een LocalDateTime-object maken

Als we weten dat we een specifieke tijdzone voor de hele applicatie gebruiken, kunnen we de standaardtijdzone instellen:

DateTimeZone.setDefault (DateTimeZone.UTC);

Vanaf nu worden alle datum- en tijdbewerkingen, tenzij anders gespecificeerd, weergegeven in de UTC-tijdzone.

Om alle beschikbare tijdzones te zien, kunnen we de methode gebruiken getAvailableIDs ():

DateTimeZone.getAvailableIDs ()

Als we de datum of tijd in een specifieke tijdzone moeten weergeven, kunnen we elk van de klassen gebruiken Lokale tijd, LocalDate, LocalDateTime, Datum Tijd en specificeer in de constructor het DateTimeZone voorwerp:

DateTime dateTimeInChicago = nieuwe DateTime (DateTimeZone.forID ("America / Chicago")); DateTime dateTimeInBucharest = nieuwe DateTime (DateTimeZone.forID ("Europa / Boekarest")); LocalDateTime localDateTimeInChicago = nieuwe LocalDateTime (DateTimeZone.forID ("America / Chicago"));

Ook kunnen we bij het converteren tussen deze klassen de gewenste tijdzone specificeren. De methode toDateTime () accepteert een DateTimeZone object en daten() accepteert java.util.TimeZone-object:

DateTime geconverteerdDateTime = localDateTimeInChicago.toDateTime (DateTimeZone.forID ("Europa / Boekarest")); Datum geconverteerdDate = localDateTimeInChicago.toDate (TimeZone.getTimeZone ("Europa / Boekarest"));

8. Conclusie

Joda-Time is een fantastische bibliotheek die begon met het belangrijkste doel om de problemen in de JDK met betrekking tot datum- en tijdbewerkingen op te lossen. Het werd al snel de de facto bibliotheek voor datum- en tijdafhandeling en onlangs zijn de belangrijkste concepten ervan geïntroduceerd in Java 8.

Het is belangrijk op te merken dat de auteur het overweegt "Om een ​​grotendeels voltooid project te zijn" en beveelt aan om de bestaande code te migreren om de Java 8-implementatie te gebruiken.

De broncode voor het artikel is beschikbaar op GitHub.