پکیج java.time.temporal مجموعهای از Interface ها، کلاسها و Enum ها را ارائه میدهد که از کد تاریخ و زمان — و بهویژه محاسبات تاریخ و زمان — پشتیبانی میکنند.
این Interface ها برای استفاده در پایینترین سطح طراحی شدهاند. کد برنامهی معمولی باید متغیرها و پارامترها را بر اساس نوع Concrete مانند LocalDate یا ZonedDateTime تعریف کند، نه بر اساس Interface Temporal. این دقیقاً مثل تعریف یک متغیر از نوع String به جای CharSequence است.
Interface Temporal چارچوبی برای دسترسی به اشیاء مبتنی بر Temporal فراهم میکند و توسط کلاسهای مبتنی بر Temporal مانند Instant، LocalDateTime و ZonedDateTime پیادهسازی میشود. این Interface متدهایی برای اضافه یا کم کردن واحدهای زمانی ارائه میدهد که حسابهای مبتنی بر زمان را در کلاسهای مختلف تاریخ و زمان آسان و یکپارچه میکند. Interface TemporalAccessor نسخهی فقط-خواندنی Interface Temporal را ارائه میدهد.
اشیاء Temporal و TemporalAccessor هر دو بر اساس Field تعریف شدهاند، همانطور که در Interface TemporalField مشخص شده است. Enum ChronoField پیادهسازی Concrete Interface TemporalField است و مجموعهی غنیای از ثابتهای تعریفشده مانند DAY_OF_WEEK، MINUTE_OF_HOUR و MONTH_OF_YEAR را ارائه میدهد.
واحدهای این Field ها توسط Interface TemporalUnit مشخص میشوند. Enum ChronoUnit Interface TemporalUnit را پیادهسازی میکند. Field ChronoField.DAY_OF_WEEK ترکیبی از ChronoUnit.DAYS و ChronoUnit.WEEKS است. Enum های ChronoField و ChronoUnit در بخشهای بعدی مورد بحث قرار میگیرند.
متدهای حسابی در Interface Temporal پارامترهایی بر اساس مقادیر TemporalAmount نیاز دارند. کلاسهای Period و Duration (که در بخش Period و Duration مورد بحث قرار گرفتهاند) Interface TemporalAmount را پیادهسازی میکنند.
Enum ChronoField که Interface TemporalField را پیادهسازی میکند، مجموعهی غنیای از ثابتها برای دسترسی به مقادیر تاریخ و زمان ارائه میدهد. چند مثال: CLOCK_HOUR_OF_DAY، NANO_OF_DAY و DAY_OF_YEAR. این Enum میتواند جنبههای مفهومی زمان مانند هفتهی سوم سال، ساعت یازدهم روز یا اولین دوشنبهی ماه را بیان کند. وقتی با یک Temporal از نوع ناشناخته مواجه شدید، میتوانید از متد TemporalAccessor.isSupported(TemporalField) برای بررسی پشتیبانی یک Field خاص استفاده کنید. خط کد زیر false برمیگرداند که نشان میدهد LocalDate از ChronoField.CLOCK_HOUR_OF_DAY پشتیبانی نمیکند:
boolean isSupported = LocalDate.now().isSupported(ChronoField.CLOCK_HOUR_OF_DAY);
فیلدهای اضافی مختص سیستم تقویم ISO-8601 در کلاس IsoFields تعریف شدهاند. مثالهای زیر نحوهی دریافت مقدار یک Field با استفاده از ChronoField و IsoFields را نشان میدهند:
time.get(ChronoField.MILLI_OF_SECOND)
int qoy = date.get(IsoFields.QUARTER_OF_YEAR);
دو کلاس دیگر فیلدهای اضافی مفیدی تعریف میکنند: WeekFields و JulianFields.
Enum ChronoUnit Interface TemporalUnit را پیادهسازی میکند و مجموعهای از واحدهای استاندارد بر اساس تاریخ و زمان، از میلیثانیه تا هزاره، ارائه میدهد. توجه کنید که تمام ChronoUnit ها توسط همهی کلاسها پشتیبانی نمیشوند. بهعنوان مثال، کلاس Instant از ChronoUnit.MONTHS یا ChronoUnit.YEARS پشتیبانی نمیکند. کلاسهای Date-Time API متد isSupported(TemporalUnit) دارند که برای بررسی پشتیبانی یک کلاس از واحد زمانی خاص مفید است. فراخوانی زیر isSupported() false برمیگرداند که تأیید میکند کلاس Instant از ChronoUnit.DAYS پشتیبانی نمیکند:
Instant instant = Instant.now();
boolean isSupported = instant.isSupported(ChronoUnit.DAYS);
Interface TemporalAdjuster در پکیج java.time.temporal متدهایی ارائه میدهد که مقداری از نوع Temporal میگیرند و مقدار تنظیمشده برمیگردانند. Adjuster ها با هر نوع مبتنی بر Temporal قابل استفاده هستند.
اگر یک Adjuster با ZonedDateTime استفاده شود، تاریخ جدیدی محاسبه میشود که مقادیر اصلی زمان و منطقهی زمانی را حفظ میکند.
کلاس TemporalAdjusters (با s انتهایی) مجموعهای از Adjuster های ازپیشتعریفشده برای پیدا کردن اولین یا آخرین روز ماه، اولین یا آخرین روز سال، آخرین چهارشنبهی ماه یا اولین سهشنبه پس از یک تاریخ مشخص ارائه میدهد. این Adjuster ها بهصورت متدهای Static تعریف شدهاند و برای استفاده با دستور Static Import طراحی شدهاند.
مثال زیر از چندین متد TemporalAdjusters همراه با متد with تعریفشده در کلاسهای مبتنی بر Temporal استفاده میکند تا تاریخهای جدیدی بر اساس تاریخ اصلی ۱۵ اکتبر ۲۰۰۰ محاسبه کند:
LocalDate date = LocalDate.of(2000, Month.OCTOBER, 15);
DayOfWeek dotw = date.getDayOfWeek();
System.out.printf("%s is on a %s%n", date, dotw);
System.out.printf("first day of Month: %s%n",
date.with(TemporalAdjusters.firstDayOfMonth()));
System.out.printf("first Monday of Month: %s%n",
date.with(TemporalAdjusters.firstInMonth(DayOfWeek.MONDAY)));
System.out.printf("last day of Month: %s%n",
date.with(TemporalAdjusters.lastDayOfMonth()));
System.out.printf("first day of next Month: %s%n",
date.with(TemporalAdjusters.firstDayOfNextMonth()));
System.out.printf("first day of next Year: %s%n",
date.with(TemporalAdjusters.firstDayOfNextYear()));
System.out.printf("first day of Year: %s%n",
date.with(TemporalAdjusters.firstDayOfYear()));
خروجی:
2000-10-15 is on a SUNDAY
first day of Month: 2000-10-01
first Monday of Month: 2000-10-02
last day of Month: 2000-10-31
first day of next Month: 2000-11-01
first day of next Year: 2001-01-01
first day of Year: 2000-01-01
میتوانید Adjuster سفارشی خودتان را هم بسازید. برای این کار کلاسی مینویسید که Interface TemporalAdjuster را با متد adjustInto(Temporal) پیادهسازی کند. مثال زیر Adjuster سفارشی PaydayAdjuster است. این Adjuster تاریخ دریافتی را ارزیابی کرده و روز حقوق بعدی را برمیگرداند، با فرض اینکه روز حقوق دو بار در ماه است: ۱۵ و آخر ماه. اگر تاریخ محاسبهشده در روز تعطیل باشد، جمعهی قبل در نظر گرفته میشود. سال تقویمی فعلی فرض شده است.
public class PaydayAdjuster implements TemporalAdjuster {
/**
* متد adjustInto یک نمونهی Temporal میگیرد
* و یک LocalDate تنظیمشده برمیگرداند.
* اگر پارامتر ورودی LocalDate نباشد، DateTimeException پرتاب میشود.
*/
public Temporal adjustInto(Temporal input) {
LocalDate date = LocalDate.from(input);
int day;
if (date.getDayOfMonth() < 15) {
day = 15;
} else {
day = date.with(TemporalAdjusters.lastDayOfMonth()).getDayOfMonth();
}
date = date.withDayOfMonth(day);
if (date.getDayOfWeek() == DayOfWeek.SATURDAY ||
date.getDayOfWeek() == DayOfWeek.SUNDAY) {
date = date.with(TemporalAdjusters.previous(DayOfWeek.FRIDAY));
}
return input.with(date);
}
}
این Adjuster دقیقاً مثل یک Adjuster ازپیشتعریفشده و با استفاده از متد with() فراخوانی میشود. مثال زیر را در نظر بگیرید:
LocalDate nextPayday = date.with(new PaydayAdjuster());
در سال ۲۰۱۳ هر دو تاریخ ۱۵ ژوئن و ۳۰ ژوئن در روز تعطیل قرار دارند. اجرای مثال بالا با تاریخهای ۳ ژوئن و ۱۸ ژوئن (در سال ۲۰۱۳) نتایج زیر را تولید میکند:
Given the date: 2013 Jun 3
the next payday: 2013 Jun 14
Given the date: 2013 Jun 18
the next payday: 2013 Jun 28
TemporalQuery میتواند برای بازیابی اطلاعات از یک شیء مبتنی بر Temporal استفاده شود.
کلاس TemporalQueries (با s انتهایی) چندین Query ازپیشتعریفشده ارائه میدهد، از جمله متدهایی که وقتی برنامه نمیتواند نوع شیء مبتنی بر Temporal را شناسایی کند مفید هستند. مانند Adjuster ها، Query های ازپیشتعریفشده بهصورت متدهای Static تعریف شدهاند و برای استفاده با دستور Static Import طراحی شدهاند.
Query مربوط به دقیقبودن (Precision)، بهعنوان مثال، کوچکترین ChronoUnit را که یک شیء مبتنی بر Temporal خاص میتواند برگرداند، نشان میدهد. مثال زیر از Query Precision روی چند نوع شیء مبتنی بر Temporal استفاده میکند:
TemporalQuery<TemporalUnit> query = TemporalQueries.precision();
System.out.printf("LocalDate precision is %s%n",
LocalDate.now().query(query));
System.out.printf("LocalDateTime precision is %s%n",
LocalDateTime.now().query(query));
System.out.printf("Year precision is %s%n",
Year.now().query(query));
System.out.printf("YearMonth precision is %s%n",
YearMonth.now().query(query));
System.out.printf("Instant precision is %s%n",
Instant.now().query(query));
خروجی:
LocalDate precision is Days
LocalDateTime precision is Nanos
Year precision is Years
YearMonth precision is Months
Instant precision is Nanos
میتوانید Query سفارشی خودتان را هم بسازید. یک روش نوشتن کلاسی است که Interface TemporalQuery را با متد queryFrom(TemporalAccessor) پیادهسازی کند. اولین Query سفارشی در کلاس FamilyVacations پیادهسازی شده که Interface TemporalQuery را اعمال میکند. متد queryFrom() تاریخ دریافتی را با تاریخهای تعطیلات برنامهریزیشده مقایسه کرده و اگر تاریخ در آن بازهها قرار داشته باشد true برمیگرداند.
public class FamilyVacations implements TemporalQuery<Boolean> {
// اگر تاریخ دریافتی در یکی از تعطیلات خانوادگی باشد، true برمیگرداند.
// چون Query فقط ماه و روز را مقایسه میکند، حتی اگر نوع Temporal
// متفاوت باشد هم بررسی با موفقیت انجام میشود.
public Boolean queryFrom(TemporalAccessor date) {
int month = date.get(ChronoField.MONTH_OF_YEAR);
int day = date.get(ChronoField.DAY_OF_MONTH);
// دیزنیلند در تعطیلات بهاری
if ((month == Month.APRIL.getValue()) && ((day >= 3) && (day <= 8)))
return Boolean.TRUE;
// دور هم جمعی خانواده اسمیت در دریاچه ساگاتاک
if ((month == Month.AUGUST.getValue()) && ((day >= 8) && (day <= 14)))
return Boolean.TRUE;
return Boolean.FALSE;
}
}
میتوانید از این TemporalQuery با الگوی زیر استفاده کنید:
// تعریف یک سال، یک ماه و یک روز
LocalDate = date = LocalDate.of(year, month, day);
boolean isFamilyVacation = date.query(new FamilyVacations());
Query سفارشی دوم در کلاس FamilyBirthdays پیادهسازی شده. این کلاس متد isFamilyBirthday() دارد که تاریخ دریافتی را با چندین تاریخ تولد مقایسه کرده و اگر مطابقت داشته باشد TRUE برمیگرداند.
public class FamilyBirthdays {
// اگر تاریخ دریافتی با یکی از تولدهای خانوادگی یکسان باشد، true برمیگرداند.
// چون Query فقط ماه و روز را مقایسه میکند، حتی اگر نوع Temporal
// متفاوت باشد هم بررسی با موفقیت انجام میشود.
public static Boolean isFamilyBirthday(TemporalAccessor date) {
int month = date.get(ChronoField.MONTH_OF_YEAR);
int day = date.get(ChronoField.DAY_OF_MONTH);
// تولد آنژی در ۳ آوریل است
if ((month == Month.APRIL.getValue()) && (day == 3))
return Boolean.TRUE;
// تولد سو در ۱۸ ژوئن است
if ((month == Month.JUNE.getValue()) && (day == 18))
return Boolean.TRUE;
// تولد جو در ۲۹ مه است
if ((month == Month.MAY.getValue()) && (day == 29))
return Boolean.TRUE;
return Boolean.FALSE;
}
}
کلاس FamilyBirthdays Interface TemporalQuery را پیادهسازی نمیکند و میتواند بهعنوان بخشی از یک Lambda Expression استفاده شود. کد زیر نحوهی فراخوانی هر دو Query سفارشی را نشان میدهد.
// فراخوانی Query بدون استفاده از Lambda Expression
Boolean isFamilyVacation = date.query(new FamilyVacations());
// فراخوانی Query با استفاده از Lambda Expression
Boolean isFamilyBirthday = date.query(FamilyBirthdays::isFamilyBirthday);
if (isFamilyVacation.booleanValue() || isFamilyBirthday.booleanValue())
System.out.printf("%s is an important date!%n", date);
else
System.out.printf("%s is not an important date.%n", date);
این محتوا کاملا رایگان توسط تیم کدلپر ترجمه شده و در اختیار شما کاربران عزیز قرار گرفته است، هر گونه کپی برداری برای مقاصد غیر رایگان و بدون ذکر منبع، مورد پیگیری قانونی قرار میگیرد.
ترجمه شده از منبع: https://dev.java/learn/