❤️ About the author: a high-quality creator in the Java field 🏆, Blog expert certification 🏆
❤️ Technical work should be rewarded
❤️ give the thumbs-up 👍 Collection ⭐ Look again and form a habit
Hello, I'm Xiao xuzhu. Before, some fans talked to me privately and asked if they could sort out the knowledge points of JAVA8's new date and time API (JSR-310). The answer is yes, who let me pet powder. Because the content is too much (more than 100000 words), it will be divided into multiple articles to write.
That's all for gossip. Please see the text below.
Introduction to classes commonly used for calculation
The following describes several classes commonly used for calculation in java8:
- Duration: represents the amount of time in seconds and nanoseconds
- Period: indicates the amount of time on mm / DD / yy
- TemporalUnit: the basic unit of date and time
- TemporalField: attribute of date and time
- ValueRange: indicates the value range
Duration
Duration class description
Package path: java.time.Duration
public final class Duration implements TemporalAmount, Comparable<Duration>, Serializable { private final long seconds; private final int nanos; ... }
Duration is the implementation class of TemporalAmount. The class contains two variables, seconds and nanos, so duration is a time quantity composed of seconds and nanoseconds.
A Duration instance is immutable. After an object is created, its value cannot be changed.
Common usage of Duration
Create Duration object
Duration is suitable for shorter processing time and requires higher accuracy. We can use the between() method to compare the difference between two moments:
Instant first = Instant.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Instant second = Instant.now(); Duration duration = Duration.between(first, second); System.out.println(duration);
The Duration object can be obtained through the LocalDateTime class
LocalDateTime first = LocalDateTime.of(2021, 8, 30, 23, 14, 20); LocalDateTime second = LocalDateTime.of(2021, 8, 30, 23, 13, 0); Duration duration = Duration.between(first, second); System.out.println(duration);
Time to access Duration
The second and nanosecond attributes can be obtained from the Duration object. But there is no millisecond attribute, which is different from System.getCurrentTimeMillis().
Instant first = Instant.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Instant second = Instant.now(); Duration duration = Duration.between(first, second); System.out.println(duration); System.out.println("second:"+duration.getSeconds()); System.out.println("Nanosecond:"+duration.getNano());
The whole time can be converted into other units, such as nanosecond, millisecond, minute, hour and day
Instant first = Instant.now(); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } Instant second = Instant.now(); Duration duration = Duration.between(first, second); System.out.println(duration); System.out.println("second:"+duration.getSeconds()); System.out.println("Nanosecond:"+duration.getNano()); System.out.println("nanosecond:"+duration.toNanos()); System.out.println("millisecond:"+duration.toMillis()); System.out.println("Points:"+duration.toMinutes()); System.out.println("Hours:"+duration.toHours()); System.out.println("Days:"+duration.toDays());
It can be seen from the figure that the getNano method is different from the toNanos method. The former is to obtain the part of the time less than 1s, and the latter is to convert the whole time into nanoseconds.
Duration calculation
plusNanos() plusMillis() plusSeconds() plusMinutes() plusHours() plusDays() minusNanos() minusMillis() minusSeconds() minusMinutes() minusHours() minusDays()
Take plusSeconds and minusSeconds as examples:
LocalDateTime first = LocalDateTime.of(2021, 8, 30, 23, 14, 20); LocalDateTime second = LocalDateTime.of(2021, 8, 30, 23, 13, 0); Duration duration = Duration.between(first, second); System.out.println(duration); Duration duration1 = duration.plusSeconds(10); System.out.println("plusSeconds After:"+duration); System.out.println("plusSeconds Post new Duration Object:"+duration1); Duration duration2 = duration.minusSeconds(10); System.out.println("minusSeconds After:"+duration); System.out.println("minusSeconds Post new Duration Object:"+duration2);
It can be seen from the above verification that after these calculation methods are executed, a new Duration object will be returned, and the original Duration object will remain unchanged.
Period
Period class description
Package path: java.time.Period
public final class Period implements ChronoPeriod, Serializable { /** * The number of years. */ private final int years; /** * The number of months. */ private final int months; /** * The number of days. */ private final int days; ... }
Period is the implementation class of ChronoPeriod. The class contains two variables: years, months and days. Therefore, period is a time quantity composed of year, month and day.
Common usage of Period
Create Period object
LocalDate first = LocalDate.of(2021, 8, 29); LocalDate second = LocalDate.of(2022, 9, 30); Period period = Period.between(first, second); System.out.println(period);
Time to access Period
LocalDate first = LocalDate.of(2021, 8, 28); LocalDate second = LocalDate.of(2022, 10, 31); Period period = Period.between(first, second); System.out.println(period); System.out.println("year:"+period.getYears()); System.out.println("Month:"+period.getMonths()); System.out.println("Date:"+period.getDays());
You can convert the whole time into other units, months
LocalDate first = LocalDate.of(2021, 8, 29); LocalDate second = LocalDate.of(2022, 9, 30); Period period = Period.between(first, second); System.out.println(period); System.out.println("month:"+period.toTotalMonths());
It can be seen from the figure that the getMonths method is different from the totalmonths method. The former is to obtain the month of this period, and the latter is to convert the whole time into the length in months.
Totalmonths source code:
public long toTotalMonths() { return years * 12L + months; // no overflow }
Duration calculation
plusDays() plusMonths() plusYears() minusDays() minusMonths() minusYears()
Take plusMonths and minusMonths as examples:
LocalDate first = LocalDate.of(2021, 8, 28); LocalDate second = LocalDate.of(2022, 10, 31); Period period = Period.between(first, second); System.out.println(period); Period period1 = period.plusMonths(1); System.out.println("plusMonths After:"+period); System.out.println("plusMonths Post new Period Object:"+period1); Period period2 = period.minusMonths(1); System.out.println("minusMonths After:"+period); System.out.println("minusMonths Post new Period Object:"+period2);
It can be seen from the above verification that after these calculation methods are executed, a new Period object will be returned, and the original Period object will remain unchanged.
TemporalUnit
TemporalUnit class description
Package path: java.time.temporary.temporalunit
public interface TemporalUnit { ... } public enum ChronoUnit implements TemporalUnit { private final String name; private final Duration duration; ... }
The main implementation class of TemporalUnit is the enumeration type chrononunit
A chrononunit member maintains a string name attribute name and an instance of the Duration type.
Chrononunit enumerates the standard date time unit collection, that is, the commonly used year, month, day, hour, minute, second, millisecond, microsecond and nanosecond. The time amount of these time units and the time represented are defined in this enumeration class.
public enum ChronoUnit implements TemporalUnit { NANOS("Nanos", Duration.ofNanos(1)), MICROS("Micros", Duration.ofNanos(1000)), MILLIS("Millis", Duration.ofNanos(1000_000)), SECONDS("Seconds", Duration.ofSeconds(1)), MINUTES("Minutes", Duration.ofSeconds(60)), HOURS("Hours", Duration.ofSeconds(3600)), HALF_DAYS("HalfDays", Duration.ofSeconds(43200)), DAYS("Days", Duration.ofSeconds(86400)), WEEKS("Weeks", Duration.ofSeconds(7 * 86400L)), MONTHS("Months", Duration.ofSeconds(31556952L / 12)), YEARS("Years", Duration.ofSeconds(31556952L)), DECADES("Decades", Duration.ofSeconds(31556952L * 10L)), CENTURIES("Centuries", Duration.ofSeconds(31556952L * 100L)), MILLENNIA("Millennia", Duration.ofSeconds(31556952L * 1000L)), ERAS("Eras", Duration.ofSeconds(31556952L * 1000_000_000L)), FOREVER("Forever", Duration.ofSeconds(Long.MAX_VALUE, 999_999_999)); private final String name; private final Duration duration; private ChronoUnit(String name, Duration estimatedDuration) { this.name = name; this.duration = estimatedDuration; } ··· }
Common usage of chrononunit
LocalDateTime localDateTime = LocalDateTime.of(2021, 8, 30, 23, 14, 20); LocalDateTime offset = localDateTime.plus(1, ChronoUnit.DAYS); // Not the same object Assert.assertNotSame(localDateTime, offset); System.out.println(offset);
TemporalField
TemporalField class description
Package path: java.time.temporary.temporalfield
public interface TemporalField { ... } public enum ChronoField implements TemporalField { private final String name; private final TemporalUnit baseUnit; private final TemporalUnit rangeUnit; private final ValueRange range; ... }
The main implementation class of TemporalField is the enumeration type ChronoField
A ChronoField member will maintain a string name attribute name, a TemporalUnit base unit baseUnit, a TemporalUnit range unit and a ValueRange type range to represent the range of the current attribute.
public enum ChronoField implements TemporalField { //Nanoseconds per second NANO_OF_SECOND("NanoOfSecond", NANOS, SECONDS, ValueRange.of(0, 999_999_999)) //Seconds in a minute SECOND_OF_MINUTE("SecondOfMinute", SECONDS, MINUTES, ValueRange.of(0, 59), "second") //Minutes in an hour MINUTE_OF_HOUR("MinuteOfHour", MINUTES, HOURS, ValueRange.of(0, 59), "minute") //How many hours are there in a morning or an afternoon CLOCK_HOUR_OF_AMPM("ClockHourOfAmPm", HOURS, HALF_DAYS, ValueRange.of(1, 12)) //Hours of the day CLOCK_HOUR_OF_DAY("ClockHourOfDay", HOURS, DAYS, ValueRange.of(1, 24)) //Morning or afternoon AMPM_OF_DAY("AmPmOfDay", HALF_DAYS, DAYS, ValueRange.of(0, 1), "dayperiod") //What day of the week DAY_OF_WEEK("DayOfWeek", DAYS, WEEKS, ValueRange.of(1, 7), "weekday") //Days of the current month DAY_OF_MONTH("DayOfMonth", DAYS, MONTHS, ValueRange.of(1, 28, 31), "day") //Number of days in the current year DAY_OF_YEAR("DayOfYear", DAYS, YEARS, ValueRange.of(1, 365, 366)) //Weeks of the current month ALIGNED_WEEK_OF_MONTH("AlignedWeekOfMonth", WEEKS, MONTHS, ValueRange.of(1, 4, 5)) //Number of weeks in the current year ALIGNED_WEEK_OF_YEAR("AlignedWeekOfYear", WEEKS, YEARS, ValueRange.of(1, 53)) //Take the first day of each month as Monday, and then calculate the day of the week ALIGNED_DAY_OF_WEEK_IN_MONTH("AlignedDayOfWeekInMonth", DAYS, WEEKS, ValueRange.of(1, 7)) //Take the first day of each month as Monday, and then calculate the day of the week ALIGNED_DAY_OF_WEEK_IN_YEAR("AlignedDayOfWeekInYear", DAYS, WEEKS, ValueRange.of(1, 7)) //Number of months in the current year MONTH_OF_YEAR("MonthOfYear", MONTHS, YEARS, ValueRange.of(1, 12), "month") private final TemporalUnit baseUnit; private final String name; private final TemporalUnit rangeUnit; private final ValueRange range; private final String displayNameKey; ... }
Common usage of ChronoField
ALIGNED_WEEK_OF_MONTH and ALIGNED_DAY_OF_WEEK_IN_MONTH usage example
//Every seven days a week, 2021-08-31 is Tuesday, and the corresponding value is 3 int num = LocalDate.of(2021, 8, 31).get(ChronoField.ALIGNED_DAY_OF_WEEK_IN_MONTH); System.out.println(num); //The fifth week of this month 2021-08-31 num = LocalDate.of(2021, 8, 31).get(ChronoField.ALIGNED_WEEK_OF_MONTH); System.out.println(num);
ValueRange
ValueRange class description
ValueRange indicates the value range.
public final class ValueRange implements Serializable { /** * The smallest minimum value.minimum value */ private final long minSmallest; /** * The largest minimum value.Maximum possible minimum */ private final long minLargest; /** * The smallest maximum value.Minimum possible maximum */ private final long maxSmallest; /** * The largest maximum value.Maximum */ private final long maxLargest; ... }
Common usage of ValueRange
ValueRange valueRange = ValueRange.of(1L, 10000L); System.out.println(valueRange); valueRange = ValueRange.of(1L, 5L, 10000L, 50000L); System.out.println(valueRange);
LocalDateTime localDateTime = LocalDateTime.of(2021, 8, 30, 23, 14, 20); ValueRange valueRange = localDateTime.range(ChronoField.DAY_OF_MONTH); System.out.println(valueRange.getMinimum()); System.out.println(valueRange.getMaximum()); System.out.println(valueRange.getLargestMinimum()); System.out.println(valueRange.getSmallestMaximum());
Chronology determines whether a leap year
To judge whether leap years are provided by Chronology, we usually use the Chronology under ISO, which is IsoChronology.
Look at the code implementation
@Override public boolean isLeapYear(long prolepticYear) { return ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0); }
Good refined code, worthy of our study
Basic judgment method of leap year:
1. Non integral hundred years: leap years are those that can be divided by 4. (for example, 2004 is a leap year, and 2001 is not a leap year)
2. Whole hundred years: leap years can be divided by 400. (for example, 2000 is a leap year and 1900 is not a leap year)
((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0);
This code uses two conditions. If both conditions are met, it is a leap year.
- (prolepticYear & 3) == 0
- (prolepticYear % 100) != 0 || (prolepticYear % 400) == 0
(prolepticyear & 3) = = 0 uses the and operator "&", and its usage law is as follows:
If the median of both operands is 1, the result is 1, otherwise the result is 0.
The binary of 3 is 011, and the purpose of prolepticyear & 3 is to retain the last two binary digits, and then judge whether the last two binary digits are equal to 0. If it is equal to 0, it is proved that it can be divided by 4. Leap years must meet the condition that they are multiples of 4;
(prolepticYear % 100) != 0 | (prolepticyear% 400) = = 0, which is easy to understand. See whether it is a multiple of 100 or 400.
Moreover, Xiao xuzhu found that the implementation code logic used by java.time.Year#isLeap() is the same
public static boolean isLeap(long year) { return ((year & 3) == 0) && ((year % 100) != 0 || (year % 400) == 0); }
Even the code written by the giant has the problem of reusability
IsoChronology above is the implementation of isLeapYear for the Chronology interface, and isLeapYear for implementation classes such as MinguoChronology, which uses the isLeapYear method of IsoChronology.
//MinguoChronology public boolean isLeapYear(long prolepticYear) { return IsoChronology.INSTANCE.isLeapYear(prolepticYear + YEARS_DIFFERENCE); }
Giant has considered reuse. It has been reused in MinguoChronology and other implementation classes.
java.time.Year#isLeap() has high priority because it is a static method. isoChronology * * you can quote Year.isLeap**
Year * * cannot quote Chronology.isLeapYear * *.
Bloggers found that there is already a reference to Year.isLeap in resolveYMD * * of IsoChronology * *.
In order to reduce the external class dependency, some tool classes will rewrite the underlying methods to avoid the class dependency of external classes (or not under a package). This has been used and can not be justified. Therefore, the code has the problem of reusability.
actual combat
int year = 2020; System.out.println(Year.isLeap(year)); System.out.println(IsoChronology.INSTANCE.isLeapYear(year)); LocalDate localDate = LocalDate.of(2021,9,7); LocalDateTime localDateTime = LocalDateTime.now(); System.out.println(localDate.isLeapYear()); System.out.println(localDateTime.toLocalDate().isLeapYear());
Compare the sequence of dates and times
Basically, there are four comparison methods: compareTo(), isBefore(), isAfter(), and equals()
Compare - LocalDate
LocalDate localDate1 = LocalDate.of(2021, 8, 14); // Compare the specified date with the parameter date and return a positive number, then the specified date and time is later (the number is larger): 13 int i = localDate1.compareTo(LocalDate.of(2021, 8, 1)); System.out.println(i); // Compare whether the specified date is earlier than the parameter date (true is earlier): true System.out.println(localDate1.isBefore(LocalDate.of(2021,8,31))); // Compare whether the specified date is later than the parameter date (true is later): false System.out.println(localDate1.isAfter(LocalDate.of(2021,8,31))); // Compare whether two dates are equal: true System.out.println(localDate1.isEqual(LocalDate.of(2021, 8, 14)));
Compare - LocalTime
LocalTime localTime1 = LocalTime.of(23, 26, 30); LocalTime localTime2 = LocalTime.of(23, 26, 32); // When comparing the two times, the large returns 1, the small returns - 1, and the same returns 0: - 1 System.out.println(localTime1.compareTo(localTime2)); // Compare whether the specified time is earlier than the parameter time (true is earlier): true System.out.println(localTime1.isBefore(localTime2)); // Compare whether the specified time is later than the parameter time (true is later): false System.out.println(localTime1.isAfter(localTime2)); // Compare whether two times are equal: true System.out.println(localTime1.equals(LocalTime.of(23, 26, 30)));
Compare - OffsetDateTime
LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20); OffsetDateTime offsetDateTime1 = OffsetDateTime.of(localDateTime1, ZoneOffset.ofHours(8)); OffsetDateTime offsetDateTime3 = OffsetDateTime.of(localDateTime1, ZoneOffset.ofHours(8)); LocalDateTime localDateTime2 = LocalDateTime.of(2021, 8, 15, 13, 14, 30); OffsetDateTime offsetDateTime2 = OffsetDateTime.of(localDateTime2, ZoneOffset.ofHours(8)); // When comparing the two times, the large returns 1, the small returns - 1, and the same returns 0: - 1 System.out.println(offsetDateTime1.compareTo(offsetDateTime2)); // Compare whether the specified time is earlier than the parameter time (true is earlier): true System.out.println(offsetDateTime1.isBefore(offsetDateTime2)); // Compare whether the specified time is later than the parameter time (true is later): false System.out.println(offsetDateTime1.isAfter(offsetDateTime2)); // Compare whether two times are equal: true System.out.println(offsetDateTime1.equals(offsetDateTime3));
Compare - OffsetTime
LocalTime localTime1 = LocalTime.of( 13, 14, 20); OffsetTime offsetTime1 = OffsetTime.of(localTime1, ZoneOffset.ofHours(8)); OffsetTime offsetTime3 = OffsetTime.of(localTime1, ZoneOffset.ofHours(8)); LocalTime localTime2 = LocalTime.of(13, 14, 30); OffsetTime offsetTime2 = OffsetTime.of(localTime2, ZoneOffset.ofHours(8)); // When comparing the two times, the large returns 1, the small returns - 1, and the same returns 0: - 1 System.out.println(offsetTime1.compareTo(offsetTime2)); // Compare whether the specified time is earlier than the parameter time (true is earlier): true System.out.println(offsetTime1.isBefore(offsetTime2)); // Compare whether the specified time is later than the parameter time (true is later): false System.out.println(offsetTime1.isAfter(offsetTime2)); // Compare whether two times are equal: true System.out.println(offsetTime1.equals(offsetTime3));
Compare ZonedDateTime
LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20); ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime1, ZoneOffset.ofHours(8)); ZonedDateTime zonedDateTime3 = ZonedDateTime.of(localDateTime1, ZoneOffset.ofHours(8)); LocalDateTime localDateTime2 = LocalDateTime.of(2021, 8, 15, 13, 14, 30); ZonedDateTime zonedDateTime2 = ZonedDateTime.of(localDateTime2, ZoneOffset.ofHours(8)); // When comparing the two times, the large returns 1, the small returns - 1, and the same returns 0: - 1 System.out.println(zonedDateTime1.compareTo(zonedDateTime2)); // Compare whether the specified time is earlier than the parameter time (true is earlier): true System.out.println(zonedDateTime1.isBefore(zonedDateTime2)); // Compare whether the specified time is later than the parameter time (true is later): false System.out.println(zonedDateTime1.isAfter(zonedDateTime2)); // Compare whether two times are equal: true System.out.println(zonedDateTime1.equals(zonedDateTime3));
Calculate the interval between dates and times
Both Duration and * * Period * * have * * between * * methods
This is not repeated. It is introduced in the common usage of Duration and Period above.
Recommend relevant articles
hutool date time series
1dateutil (time tool class) - current time and current timestamp
3dateutil (time tool class) - get various contents of the date
4dateutil (time tool class) - format time
5dateutil (time tool class) - resolves the formatted time
6dateutil (time tool class) - time offset acquisition
7dateutil (time tool class) - date calculation
8chinesedate (lunar date tool)
9localdatetimeutil (encapsulated by {@ link LocalDateTime} tool class in jdk8 +)
10TemporalAccessorUtil{@link TemporalAccessor} tool class encapsulation
other
To explore the core underlying source code of JDK, you must master the usage of native
Wanzi blog teaches you to understand the date and time related usage of java source code
Source code analysis: risks and best practices for JDK to obtain the default time zone
Today is the 9th / 100th day of continuous writing.
You can pay attention to me, praise me, comment on me and collect me.