Amikor java.time objektumokkal, például LocalDate-dal dolgozol, gyakran összetett dátumkorrekciókat kell végrehajtanod, például meg kell keresned a hónap második keddjét.
Ahelyett, hogy ezt manuálisan számolnád ki, használhatod a TemporalAdjusters osztályt.
A java.time.temporal.TemporalAdjusters segédosztály (figyeld meg a többes számú „s” végződést) számos gyakori dátumkorrekcióhoz kínál statikus metódusokat.
Ezeket a korrekciókat egy időbeli objektumon (például LocalDate-on) a .with() metódussal alkalmazod.
A with(TemporalAdjuster) használata egy új példányt ad vissza, és nem frissíti a meglévő példányt, mert a java.time objektumok megváltoztathatatlanok.
import java.time.LocalDate;
import java.time.Month;
import java.time.DayOfWeek;
import java.time.temporal.TemporalAdjusters;
LocalDate date = LocalDate.of(2024, Month.AUGUST, 15); // 2024-08-15 (a Thursday)
// Use a predefined adjuster: find the last day of the month
LocalDate lastDay = date.with(TemporalAdjusters.lastDayOfMonth());
// => 2024-08-31
Íme néhány kulcsfontosságú időbeállító, amely hasznos lehet az ütemezési számításokhoz:
A dayOfWeekInMonth(int ordinal, DayOfWeek dayOfWeek) metódussal megkeresheted egy hét valamely napjának n-edik előfordulását.
// Find the second Tuesday of August 2024
LocalDate secondTuesday = date.with(TemporalAdjusters.dayOfWeekInMonth(2, DayOfWeek.TUESDAY));
// => 2024-08-13
Használd a firstInMonth(DayOfWeek dayOfWeek) vagy a lastInMonth(DayOfWeek dayOfWeek) metódust.
// Find the last Monday of August 2024
LocalDate lastMonday = date.with(TemporalAdjusters.lastInMonth(DayOfWeek.MONDAY));
// => 2024-08-26
Az olyan időbeállítók, mint a next(), previous(), nextOrSame() és previousOrSame(), egy adott hét napjának következő vagy előző előfordulását keresik meg az aktuális dátumhoz képest.
next()/previous(): kizárja az aktuális dátumot, ha az megfelel.nextOrSame()/previousOrSame(): beleszámítja az aktuális dátumot, ha az megfelel.LocalDate thursday = LocalDate.of(2024, Month.AUGUST, 15); // A Thursday
// Find the next Thursday (exclusive)
LocalDate nextThursday = thursday.with(TemporalAdjusters.next(DayOfWeek.THURSDAY));
// => 2024-08-22
// Find the next Thursday (inclusive) - returns the same date
LocalDate nextOrSameThursday = thursday.with(TemporalAdjusters.nextOrSame(DayOfWeek.THURSDAY));
// => 2024-08-15
// Find the previous Monday (exclusive)
LocalDate previousMonday = thursday.with(TemporalAdjusters.previous(DayOfWeek.MONDAY));
// => 2024-08-12
A TemporalAdjuster funkcionális interfész, ezért saját időbeállítót is írhatsz lambda kifejezésként, amely megkapja a beállítandó időbeli objektumot, és visszaadja a beállítottat.
Ugyanúgy a .with() metódussal alkalmazod, mint az előre definiált időbeállítókat, és belül maga is használhatja azokat.
import java.time.temporal.TemporalAdjuster;
// An adjuster that moves a weekend date to the following Monday
TemporalAdjuster skipWeekend = temporal -> {
DayOfWeek day = DayOfWeek.from(temporal);
if (day == DayOfWeek.SATURDAY || day == DayOfWeek.SUNDAY) {
return temporal.with(TemporalAdjusters.next(DayOfWeek.MONDAY));
}
return temporal;
};
LocalDate saturday = LocalDate.of(2024, Month.AUGUST, 17);
LocalDate monday = saturday.with(skipWeekend);
// => 2024-08-19
A TemporalAdjusters osztály ezen időbeállítóinak használata nagyban leegyszerűsítheti a dátumkezelési feladatokat.
Jól megy a new york-i szépségszalon, amelynek a Booking Up For Beauty feladatban segítettél, és sok vendége lett törzsvendég. A törzsvendégek nem külön foglalnak minden egyes alkalomra, hanem állandó megállapodásuk van: „minden második kedd”, „a hónap utolsó péntekje” és így tovább. A tulajdonos kért tőled egy segédet, ami kiszámolja ezeknek a megállapodásoknak a dátumait, valamint a szalon saját havi rutinjának dátumait is.
Készítsd el a SalonCalendar.standingAppointment() metódust, amely egy évet, egy hónapot, egy előfordulást (1 az első, 2 a második, és így tovább) és egy hét napját kap.
A metódus visszaadja a hét adott napja adott előfordulásának dátumát a hónapon belül:
SalonCalendar calendar = new SalonCalendar();
calendar.standingAppointment(2024, Month.AUGUST, 2, DayOfWeek.TUESDAY);
// => LocalDate.of(2024, 8, 13)
Néhány törzsvendég inkább a hónap utolsó, a saját napjára eső időpontját választja.
Készítsd el a SalonCalendar.lastAppointment() metódust, amely egy évet, egy hónapot és egy hét napját kap, és visszaadja a hét adott napja utolsó előfordulásának dátumát a hónapon belül:
SalonCalendar calendar = new SalonCalendar();
calendar.lastAppointment(2024, Month.AUGUST, DayOfWeek.FRIDAY);
// => LocalDate.of(2024, 8, 30)
Egy vendég a recepción a „következő szombatot” kéri.
Ha épp szombaton kérdezi, akkor magára aznapra gondol.
Készítsd el a SalonCalendar.nextAvailable() metódust, amely egy dátumot és egy hét napját kap, és visszaadja az első olyan dátumot, amely nem korábbi a megadott dátumnál, és a hét adott napjára esik:
SalonCalendar calendar = new SalonCalendar();
calendar.nextAvailable(LocalDate.of(2024, 8, 15), DayOfWeek.SATURDAY);
// => LocalDate.of(2024, 8, 17)
calendar.nextAvailable(LocalDate.of(2024, 8, 17), DayOfWeek.SATURDAY);
// => LocalDate.of(2024, 8, 17)
A szalon minden hónap utolsó napján zárja a könyvelést.
Hétvégén azonban zárva van, ezért ha a hónap utolsó napja szombatra vagy vasárnapra esik, a könyvelést az előtte lévő pénteken zárják.
Készítsd el a SalonCalendar.bookkeepingDay() metódust, amely egy évet és egy hónapot kap, és visszaadja az adott hónap könyvelési napját:
SalonCalendar calendar = new SalonCalendar();
calendar.bookkeepingDay(2024, Month.SEPTEMBER);
// => LocalDate.of(2024, 9, 30)
calendar.bookkeepingDay(2024, Month.AUGUST);
// => LocalDate.of(2024, 8, 30)
A munkatársak fizetése minden hónap 15-én van, ugyanezzel a hétvégi szabállyal: ha a 15. szombatra vagy vasárnapra esik, a fizetésnap az előtte lévő péntek. Ahelyett, hogy másodszor is leírnád a szabályt, alakítsd újrahasznosítható korrekcióvá.
Készítsd el a SalonCalendar.precedingWorkday() metódust, amely egy TemporalAdjuster példányt ad vissza: ez a hétköznapot változatlanul hagyja, a szombatot vagy a vasárnapot pedig visszaviszi az előtte lévő péntekre.
Ezután készítsd el a SalonCalendar.payday() metódust, amely egy évet és egy hónapot kap, és ezt a korrekciót használja:
SalonCalendar calendar = new SalonCalendar();
LocalDate.of(2024, 6, 15).with(calendar.precedingWorkday());
// => LocalDate.of(2024, 6, 14)
calendar.payday(2024, Month.JUNE);
// => LocalDate.of(2024, 6, 14)
calendar.payday(2024, Month.AUGUST);
// => LocalDate.of(2024, 8, 15)
Nyugodtan térj vissza, és használd ezt a korrekciót a bookkeepingDay() metódusban is.
Iratkozz fel az Exercism-re, hogy megtanuld és elsajátítsd a(z) Java nyelvet 27 fogalom159 feladat segítségével, valódi emberi mentorálással, mindez ingyen.