❤️ Summary of JSR-310 (java8 new date and time API) of 150000 word JDK source code analysis ❤️ (JAVA small Phyllostachys pubescens, recommended Collection)

Posted by hyeteck on Sun, 26 Sep 2021 00:12:57 +0200

❤️ About the author: Hello, I'm Xiao xuzhu. High quality creators in Java 🏆, CSDN blog expert 🏆
❤️ Technical work should be rewarded
❤️ give the thumbs-up 👍 Collection ⭐ Look again and form a habit

What is the JSR specification

Explanation from Baidu Encyclopedia:

JSR is the abbreviation of Java Specification Requests, which means Java specification proposal. It is a formal request to add a standardized technical specification to the JCP(Java Community Process). Anyone can submit a JSR to add new API s and services to the Java platform. JSR has become an important standard in the Java world.

What mysterious organization is JCP

JCP (Java Community Process) is an open international organization, mainly composed of Java developers and licensees

So the standardization of JAVA is reviewed and released by this organization. I feel it's really great.

What are the members of JCP? The fire of gossip is burning

Information obtained from the official website:

For the 2020 elections, two ratifications and one electoral seat will be eliminated, thereby reducing the EC to 18 members
After the 2020 grade election, there will be 11 approved seats, 4 elected seats, 2 quasi seats (for individuals) and permanent seats held by Oracle America. The members have a staggered tenure of two years, so 8 or 9 of the 17 seats usually need approval / election every year.

Let's look at the list of approvals and elections in 2020

Those underlined are those approved and elected in 2020.

Alibaba: Alibaba was selected, and domestic enterprises were selected into JCP. It's awesome.

BellSoft: BellSoft publishes and supports the free and secure Unified Java Runtime, Liberica JDK. It can be used on most platforms and today's architectures, including microservice based architectures.

BNY Mellon: more than 11000 technical experts and developers worldwide support the bank as a leading provider of clearing, payment, custody and asset management services in global financial markets.

Java community participation

-Active approving member of the JCP Executive Committee (EC)
-Proposed Java Collections 2.0
-Committed to Java education through the working group
-Lead Java user group
-Interact with the community through presentations, blogs, code seminars
-Open source participation

JetBrains: IDEA has used it. This product is developed by JetBrains.

MicroDoc: MicroDoc is a technology-oriented software development enterprise in Germany, which provides embedded Java virtual machines for the global customer base. MicroDoc is a supporter of open standards and commercially available open source software. It is an active contributor to OpenJDK. Since 2014, MicroDoc has occupied a place in JCP EC and decided to participate in the next election period to promote J The development of AVA focuses on embedded applications in automotive, healthcare and intelligent environments.

SAP SE: SAP has more than 250000 enterprise customers and is the world's leading commercial software supplier. A large number of these SAP customers run Java based sap. Sap has been involved in JCP since 2001 and has cooperated in more than 50 jsrs. Sap has contributed to OpenJDK since 2012. It currently participates in the OpenJDK 11 update project and provides sapmach Line, a free build of OpenJDK. Sap is committed to the continued success of Java.

London Java Community: London Java Community, representing the global JUG (London Java user group) community (400000 + developers). We run "adopt JSR" and "adopt OpenJDK" to improve developers' daily participation in Java standards.

Eclipse Foundation: the eclipse foundation has been participating in the JCP Executive Committee since 2007. As the seat of the Eclipse Java IDE, Jakarta EE, MicroProfile, adorium, Eclipse Java compiler and OpenJ9, we are very committed to the Java ecosystem. Our main contribution to JCP EC is to represent the interests of the open source community and the independent implementation of the Java specification.

Ken Fogel: I am a professor of computer science and technology at Dawson college in Montreal. The task of the program is to train students, mainly to become software developers preparing for work after graduating from high school. In 2019, I became Java Champion. Five years ago, I started a free one-day conference called DawsCon in Montreal. I attracted some of the best Speakers talk to students and the local developer community. I have also spoken at JavaOne/CodeOne over the past six years.

OK! The gossip is over and back to the point.

JSR specification content

Included in the standard set of three Java versions: JAVA SE, JAVA EE, and JAVA ME.

Some jsrs are included in one or more JAVA platforms.

The following is the corresponding official website address:

Java SE

Java EE

Java ME

Click JAVA SE to come in and have a look

5The number of JSR, and the content of the same line is the name corresponding to the JSR number
Description:Describe what this JSR is used for
Status:What is the current status of this JSR
Latest Stage:Latest stage
Spec Lead:Person in charge of specification

Click the name corresponding to the JSR number to jump to the details page of the JSR content.

Status status:

StatusWhat it means
ActiveMilestone jsrs have been released in the past 12 months.
FinalJSR, which produced the final release milestone more than a year ago.
MaintenanceThe last JSR that produced a maintenance review or maintenance release milestone was more than a year ago
InactiveJsrs that have not yet generated a final or maintenance version and have not released milestones last year
WithdrawnJSR withdrawn from the JCP by the specification owner prior to final release.
RejectedA JSR that has not been approved by the Executive Committee in one of the voting stages of the JSR
DormantJsrs voted "dormant" by the Executive Committee, or jsrs that have reached the end of their natural life

Now you have a basic understanding of JSR.

JSR-310 introduction

Bloggers are studying the source code of JAVA date and time recently. Taking JSR-310 as the cut-off entrance, I will introduce JSR to you

Part I: timeline

JSR-310 took about 7 years from its inception to its release. From a small perspective, it can be seen that the release of each JSR is a fine product after careful polishing.

Part II: Team

List of specification principals and expert groups

Part III: development timeline details

Development timeline of JSR-310:

The API (JSR-310) is implemented by Stephen coleborne based on joda time project.

Stephen coleburne founded and led the joda time project and is a member of the Apache Software Foundation, focusing on Jakarta Commons. Michael Nascimento Santos founded and led the Genesis project and contributed to NetBeans, AspectWerkz and Thinlet. Michael also has five previous JSR experiences.

Part IV: Details

Description of JSR-310 specification (direct translation of official documents)

This JSR will provide java with a new and improved date and time API. The main goal is to provide a more advanced and comprehensive model for date and time operations, drawing on the lessons learned from the first two APIs of Java SE (date and calendar).

The new API will target all applications that require date and time data models. The model will override classes to replace dates and calendars, including representing dates without time, times without dates, durations, and intervals. This will improve the quality of the application code. For example, the date and time model will provide a class that explicitly defines it, instead of using int to store duration and using javadoc to describe it as days.

The new API will also address related date and time issues. These include formatting and parsing, taking into account the ISO8601 standard and its implementation, such as XML. In addition, the serialization and persistence domains will be considered.

The ultimate goal of the new API is simplicity and ease of use. The API will need to contain some powerful functionality, but it cannot obscure the standard use case. The easy-to-use part includes interaction with existing Date and Calendar classes, which will be the focus of the expert group.

Target Java platform

Java SE (Java EE also applies)

What will the proposed specification meet the needs of the Java community (direct translation of official documents)

  1. Currently, Java SE has two independent date and time APIs - java.util.date and java.util.Calendar. Java developers agree on blogs and forums that these two APIs are difficult to use. It is worth noting that both use the month index starting from 0, which is the cause of many errors. Over the years, calendars have also suffered from many errors and performance problems, mainly because they store their status internally in two different ways.
  2. A classic error (4639407) prevents the creation of certain dates in the Calendar object. You can write a series of code that can create dates in some years, but not in other years, preventing some users from entering the correct birth date. This is because the Calendar class only allows one hour of daylight saving time to be added in summer, while historically, it added two hours before and after World War II. Although this error has been fixed, if a country / region chooses to introduce a 3-hour daylight saving time gain in summer at some time in the future, the Calendar class will be destroyed again.
  3. The current Java SE API is also affected by a multithreaded environment. As we all know, immutable classes are thread safe in nature because their state cannot be changed. However, both Date and Calendar are variable, which requires programmers to explicitly consider cloning and threading. In addition, the lack of thread safety in DateTimeFormat is not well known and has become the cause of many thread problems that are difficult to track.
  4. Except for the problem of Java SE's datetime class, it has no classes for modeling other concepts. Non time zone date or time, duration, period, and interval are not represented by classes in Java se. Therefore, developers often use int to represent duration and javadoc to specify units.
  5. The lack of a comprehensive date and time model also makes many common operations more difficult than they should be. For example, calculating the number of days between two dates is a particularly difficult problem at present.
  6. The JSR will solve the problem of the complete date and time model, including date and time (with and without time zone), duration and time period, interval, format and parsing.

Part V: Download API and analysis

What is the core code contained in JSR-310

Download API document: as shown in the figure, click:

Select Download:

Open the index page

You are familiar with the directory package structure, aren't you

java.time What's in the bag java8 New date and time API

java.time contains the main API based on the ISO-8601 standard. The classes defined here represent the main date time concepts, including instant, duration, date, time, time zone and time period. They are based on the ISO calendar system, a de facto world calendar that follows the rules of the Gregorian calendar. All classes are immutable and thread safe.

The blogger recently wrote an API comparison article about the old and new date and time of java< Wanzi blog teaches you to understand the date and time related usage of java source code>

If you are interested, you can quickly understand the differences between the two sets of APIs and the advantages of the new API.

(1) JSR-310: ZoneId time zone and offset

Geographical knowledge review

time zone

Because countries and regions in the world have different longitude and local time, they will be divided into different time zones.
The formal time zone division includes 24 time zones, each time zone is represented by an English letter, and one time zone is divided every 15 ° longitude.
In order to overcome the confusion of time, an international longitude Conference (also known as the international meridian Conference) held in Washington in 1884 stipulated that the world was divided into 24 time zones (12 time zones in the East and 12 time zones in the West), and Britain (the former site of Greenwich Observatory) was defined as the central time zone (zero time zone) East Zone 1-12 and West Zone 1-12. Each time zone spans 15 degrees longitude, and the time is exactly 1 hour. The last east zone and west zone 12 span 7.5 degrees longitude, with 180 degrees longitude in the East and West as the boundary. The time on the central longitude of each time zone is the time uniformly adopted in this time zone, which is called zone time. The time difference between the two adjacent time zones is 1 hour.
For example, the time in East 8 of China is always 1 hour earlier than that in East 7 of Thailand and 1 hour later than that in East 9 of Japan.
– quoted from Baidu Encyclopedia

The longitude distribution of time zone is shown in the list:

time zoneLongitude range of time zoneTime zone centerline
UTC(0 time zone)7.5°W~7.5°E
UTC + 1 (East Zone 1)7.5°E~22.5°E15°E
UTC + 2 (East Zone 2)22.5°E~37.5°E30°E
UTC + 3 (East Zone 3)37.5°E~52.5°E45°E
UTC + 4 (East Zone 4)52.5°E~67.5°E60°E
UTC + 5 (East Zone 5)67.5°E~82.5°E75°E
UTC + 6 (East Zone 6)82.5°E~97.5°E90°E
UTC + 7 (East Zone 7)97.5°E~112.5°E105°E
UTC + 8 (East Zone 8)112.5°E~127.5°E120°E
UTC + 9 (East Zone 9)127.5°E~142.5°E135°E
UTC + 10 (East zone 10)142.5°E~157.5°E150°E
UTC + 11 (East Zone 11)157.5°E~172.5°E165°E
Utc12 (East and west zone 12)172.5°E~172.5°W180°
Utc-11 (West Zone 11)172.5°W~157.5°W165°W
Utc-10 (West Zone 10)157.5°W~142.5°W150°W
Utc-9 (West Zone 9)142.5°W~127.5°W135°W
UTC-8 (West Zone 8)127.5°W~112.5°W120°W
Utc-7 (west 7)112.5°W~97.5°W105°W
Utc-6 (West Zone 6)97.5°W~82.5°W90°W
Utc-5 (West Zone 5)82.5°W~67.5°W75°W
Utc-4 (West Zone 4)67.5°W~52.5°W60°W
Utc-3 (West Zone 3)52.5°W~37.5°W45°W
Utc-2 (West Zone 2)37.5°W~22.5°W30°W
Utc-1 (West Zone 1)22.5°W~7.5°W15°W

In fact, one country or one province often spans two or more time zones at the same time. In order to take into account the administrative convenience, one country or one province is often divided together. For example, China has a wide territory and spans almost five time zones, but for convenience and simplicity, in fact, only the standard of Dongba time zone, namely Beijing time, is used.

UTC

Coordinated universal time, also known as world unified time, world standard time and international coordinated time. Due to the different abbreviations of English (CUT) and French (TUC), it is referred to as UTC as a compromise.
Coordinated universal time is a time measurement system based on atomic time and second length, which is as close to universal time as possible.
The accuracy of international atomic time is nanoseconds per day, while the accuracy of world time is milliseconds per day. Many application departments require the time system to be close to universal time UT. For this situation, a compromise time scale called coordinated universal time was published in 1972. In order to ensure that the difference between coordinated universal time and universal time does not exceed 0.9 seconds, positive or negative leap seconds will be added to coordinated universal time if necessary. Therefore, there will be several integer second differences between coordinated universal time and international atomic time, and the difference between them accumulates year by year. The method of second skipping (leap second) is adopted to make the time of coordinated time close to universal time, and the difference is no more than 1s. It not only maintains the uniformity of time scale, but also can approximately reflect the change of earth rotation.
– quoted from Baidu Encyclopedia

Coordinated universal time is not related to regional location and does not represent the time of a place at the current time, so the time zone should be added when saying a local time. For example, China is UTC+8.

UTC is the time standard, which divides the world into 24 time zones from UTC-12 to UTC + 12.

GMT

GMT(Greenwich Mean Time) alias: Greenwich time (sometimes translated as Greenwich), Chinese Name: universal time.

GMT refers to the standard time at Greenwich, and it is also a form of indicating the earth's rotation rate. A time measurement system based on the earth's rotation. The angle of the earth's rotation can be measured by the motion of the local meridian relative to the basic reference point on the earth. In order to measure the earth's rotation, two basic reference points are selected on the earth: the vernal equinox (see the equinox) and the solar point. The time determined from this is called stellar time and solar time respectively.
– quoted from Baidu Encyclopedia

GMT is not equal to UTC, but Greenwich is just in time zone 0. So GMT = UTC+0 is right.

CST

CST can be regarded as standard time in the United States, Australia, Cuba or China
Central Standard Time (USA) UT-6:00
Central Standard Time (Australia) UT+9:30
China Standard Time: UT + 8:00
Cuba Standard Time UT-4:00

– quoted from Baidu Encyclopedia

Therefore, pay attention to the corresponding time zone when converting CST time. This is a pit.

Central time: CST=UTC/GMT-6;

China Standard Time: CST=UTC/GMT+8;

DST

DST(Daylight Saving Time) Chinese Name: daylight saving time.

It means to set a man-made time in order to save energy. It is also called Daylight Saving Time (DST), also known as "Daylight Saving Time" and "Daylight Saving Time". The unified time adopted during the implementation of this system is called "Daylight Saving Time". Generally, in the summer when the morning is early, artificially adjust the time by one hour, which can make people get up early and go to bed early, reduce the amount of lighting, so as to make full use of lighting resources and save lighting power. The specific provisions of each country adopting Daylight Saving Time are different. Nearly 110 countries around the world implement Daylight Saving Time every year.
– quoted from Baidu Encyclopedia

The time frame for China to realize DST: 1986-1991.

ISO-8601

The international standard ISO 8601 of the international organization for standardization is the representation of date and time, which is fully known as data storage and exchange form · information exchange · representation of date and time. At present, the latest version is ISO8601:2004 in the third edition, ISO8601:1988 in the first edition and ISO8601:2000 in the second edition
– quoted from Baidu Encyclopedia

The year consists of four digits YYYY, or four or five digits with a sign represent ± YYYY. The first year of the Gregorian calendar is 0001, the first year of the Gregorian calendar is 0000, and the second year of the Gregorian calendar is - 0001.

Month and day are expressed in two digits: MM and DD.

Use only numbers as the basic format. Use the Dash "-" to interval the year, month and day as the extended format.

Hours, minutes and seconds are represented by two digits. Add a capital letter Z at the end of UTC time, and other time zones are represented by actual time and time difference. For example, 2:30:5 p.m. UTC time is expressed as 14:30:05Z or 143005Z, and Beijing time at that time is expressed as 22:30:05 + 08:00 or 223005 + 0800, which can also be simplified to 223005 + 08.

Note: do you remember the Date class of java? It is represented by ISO-8601 by default.

Before JDK8: TimeZone / offset TimeZone

Before JDK8, we used java.util.TimeZone to represent and process time zones and offsets.

**TimeZone.getDefault() * * get the time zone in which the current JVM is running. How does it get the default time zone? I have written an analysis article before. If you are interested, you can understand it. It will not be repeated here.

The JDK obtains the risks and best practices of the default time zone

Sometimes it is necessary to convert the time zone. For example, a time should be displayed in Beijing time and New York time. realization:

There is no SimpleDateFormat to format the time because it is thread unsafe. Select thread safe FastDateFormat,

Apache Commons Lang package support.

If you are interested, you can learn about the source code analysis of FastDateFormat: The SimpleDateFormat thread of java is unsafe. There is a problem. Virtual bamboo teaches you a variety of solutions

		String patternStr = "yyyy-MM-dd HH:mm:ss";
		// Beijing time (new is the time in the default time zone)
		Date bjDate = new Date();
		// Get the time zone of New York
		TimeZone newYorkTimeZone = TimeZone.getTimeZone("America/New_York");
		// Convert Beijing time to New York Date according to this time zone
		FastDateFormat fastDateFormat = FastDateFormat.getInstance(patternStr,newYorkTimeZone);
		System.out.println("This is Beijing time:" + FastDateFormat.getInstance(patternStr).format(bjDate));
		System.out.println("This is New York time:" + fastDateFormat.format(bjDate));

19-7 = 12 Beijing time is 12 hours faster than New York time.

JDK8 starts to support: time zone / offset ZoneId/ZoneOffset

In JDK8, ZoneId represents the ID of the time zone, and ZoneOffset represents the offset of Greenwich/UTC.

ZoneId is used to replace java.util.TimeZone.

Let's study ZoneId. ZoneId represents the ID of a time zone, which is determined. However, the time zone ID has corresponding rules, which are determined by java.time.zone.ZoneRules. For example, the daylight saving time rules are set by governments of various countries and may change. They are different in different years. This is left to the underlying mechanism of JDK to keep pace. We callers do not need to care (no! Care! Only when the technology is no longer a black box can we have a bottom in mind!).

How to synchronize the time zone when the rules of the time zone change

Introduction to TZUpdater tool

The TZUpdater tool provided allows you to update the installed java development kit (JDK) and Java runtime environment (JRE) software with updated time zone data to adapt to daylight saving time (DST) changes in different countries / regions. Oracle relies on time zone data publicly available through IANA's time zone database.

If you cannot use the latest JDK or JRE update version of Oracle, or if the time zone data on the latest version is not the latest available, TZUpdater tool provides a method to update the time zone data while keeping other system configurations and dependencies unchanged

TZUpdater tool usage

The TZUpdater tool is used to execute the JDK/JRE software instance of the tool. JDK/JRE software will be modified every time. To manage tools to multiple instances of JDK/JRE software.

Before running the TZUpdater tool on the installed JDK/JRE software, you must stop any running services of the JDK/JRE software on the operating system.

Run the TZUpdater tool with the following command:

java -jar tzupdater.jar options

To successfully update the time zone data, you should ensure that you have sufficient permissions to modify the JDK_HOME /jre/lib or JRE_HOME /lib directory.

If no options are specified, a usage message is displayed. To update the time zone data, use the - l or - f option.

optiondescribe
-h, --help
Print the usage to stdout and exit. If you specify this option, the other options are ignored.
-V, --versionPrint the tool version, the tzdata version in the JRE, and the tzdata version to which the tool will be updated, and exit.
-l, --location url-link-to-archive-fileCompile, test, and update JRE time zone data from the provided tzdata.tar.gz package, such as - l https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz. Supported URL protocols: http: / /, HTTPS: / /, file: / /. If no URL link is provided, the tool will use the latest IANA tzdata package located at https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz .
-f, --forceForce tzdata update. Use this option if updating to an older version of tzdata.
-v, --verboseDisplays the detailed message stdout to.

Manual upgrade

be careful:

1. Before running the TZUpdater tool on the installed JDK/JRE software, you must stop any running services of the JDK/JRE software on the operating system.

2. To successfully update the time zone data, you should ensure that you have sufficient permissions to modify the JDK_HOME /jre/lib or JRE_HOME /lib directory. (linux system: JRE directory should have write permission; windows system: run cmd as administrator)

3. If there are multiple JDK / jres on the system, the tool needs to be used in each JDK/JRE (each JDK/JRE needs to be operated once)

4. After the update is successful, restart the application service on this JDK/JRE instance (if it has not been updated, restart the server to try)

Operation steps:

1. Download the tzupdater.jar package officially provided by Oracle; Download address

https://www.oracle.com/java/technologies/javase-tzupdater-downloads.html

Put tzupdater.jar in the java directory bin directory, for example

"C:\Program Files\JAVA\java-1.8.0-openjdk-1.8.0.201\bin\tzupdater.jar";

2. Check the current time zone database version. Take windows as an example, run cmd as an administrator and switch to the directory corresponding to tzupdater.jar:

java -jar tzupdater.jar -V

3. For online update, take windows as an example, run cmd as an administrator and switch to the directory corresponding to tzupdater.jar: (choose one of the third and fourth update methods)

java -jar tzupdater.jar -l https://www.iana.org/time-zones/repository/tzdata-latest.tar.gz

As shown in the figure, it has been successfully updated to tzdata 2021a.

The updated file is placed in jre/lib/tzdb.dat, as shown in the figure. It has a backup history version.

4. Offline update: download the latest time zone data first. Download address:

https://data.iana.org/time-zones/releases/

Take windows as an example, run cmd as an administrator. Switch to the directory corresponding to tzupdater.jar:

java -jar tzupdater.jar -l file:///[path]/tzdata.tar.gz 

Note:

windows recommends that you put it in the root directory of drive C, and the path directory should not have Chinese;

Run cmd as administrator (write permission is required);

As shown in the above command, the / after file is 3

5. After the above execution, use the command to view the current time zone database version in step 2 to check whether the update is successful.

Service automation upgrade

Thinking steps:

1. Set the scheduled task (just configure the operating system) and execute the command script of tzupdater to update the time zone;

2. A new time zone service is opened to provide time zone and daylight saving time rule reading services for external deployment;

3. In the time zone service, write a synchronization button to execute the command script of tzupdater to update the time zone;

4. In the time zone service, the timeZone data is regularly written to the user-defined time zone table. It provides maintenance functions, and you can customize the addition, modification and deletion of timeZone data.

Benefits of this idea:

1. Other services do not need to stop the service to update the time. The latest time zone data can be obtained directly by calling the data of the time zone service;

2. The advantage of automation avoids the tedious manual maintenance of time zone, and manual intervention has the risk of causing problems;

3. Time zone services and other business services are split to facilitate future expansion.

System default ZoneId

	@Test
	public void timeZoneTest2(){
		System.out.println("JDK 8 Previous practice:"+TimeZone.getDefault());

		System.out.println("JDK 8 Subsequent practice:"+ZoneId.systemDefault());
	}

ZoneId.systemDefault()Method implementation is called TimeZone: 
 public static ZoneId systemDefault() {
        return TimeZone.getDefault().toZoneId();
    }

So the two results are the same (Asia/Shanghai), which is normal.

TimeZone.toZoneId() is a method added after java8.

   /**
     * Converts this {@code TimeZone} object to a {@code ZoneId}.
     *
     * @return a {@code ZoneId} representing the same time zone as this
     *         {@code TimeZone}
     * @since 1.8
     */
    public ZoneId toZoneId() {
        String id = getID();
        if (ZoneInfoFile.useOldMapping() && id.length() == 3) {
            if ("EST".equals(id))
                return ZoneId.of("America/New_York");
            if ("MST".equals(id))
                return ZoneId.of("America/Denver");
            if ("HST".equals(id))
                return ZoneId.of("America/Honolulu");
        }
        return ZoneId.of(id, ZoneId.SHORT_IDS);
    }

Specify the string to get ZoneId and get all zoneIds

		System.out.println(ZoneId.of("America/New_York"));

		System.out.println(ZoneId.of("Asia/Shanghai"));

	@Test
	public void ZoneIdTest2(){
		Set<String> zoneIds = ZoneId.getAvailableZoneIds();
		System.out.println("zoneIds Length:"+zoneIds.size());
		for(String zoneId : zoneIds){
			System.out.println(zoneId);
		}
	}

The specified string cannot be scribbled, or an error will be reported. It should be in the collection range of ZoneId.getAvailableZoneIds().

Get time zone from date

System.out.println(ZoneId.from(ZonedDateTime.now()));
			
System.out.println(ZoneId.from(ZoneOffset.of("+8")));

Obtaining the time zone from the date only supports the TemporalAccessor with the time zone, such as LocalDateTime. LocalDate is not allowed and will report an error.

		try {
			System.out.println(ZoneId.from(LocalDateTime.now()));
		}catch (Exception e){
			e.printStackTrace();
		}
		try {
			System.out.println(ZoneId.from(LocalDate.now()));
		}catch (Exception e){
			e.printStackTrace();
		}

ZoneId is an abstract class. It has two inheritance implementation classes:

  • ZoneOffset: time zone offset
  • ZoneRegion: geographic region

ZoneOffset (time zone offset)

The time zone offset is the time difference between the time zone and Greenwich/UTC, which is generally a fixed number of hours and minutes.

Min / max offset

	@Test
	public void ZoneIdTest5(){
		System.out.println("Minimum offset:" + ZoneOffset.MIN);
		System.out.println("Minimum offset:" + ZoneOffset.MAX);
		System.out.println("Center offset:" + ZoneOffset.UTC);
		// Maximum range exceeded
		System.out.println(ZoneOffset.of("+100"));
	}

If the maximum range is exceeded, an error will be reported

Time minute second construction offset

	@Test
	public void ZoneIdTest6(){
		System.out.println(ZoneOffset.ofHours(10));
		System.out.println(ZoneOffset.ofHoursMinutes(10, 10));
		System.out.println(ZoneOffset.ofHoursMinutesSeconds(10, 10, 10));

		System.out.println(ZoneOffset.ofHours(-10));
	}

Very convenient, simple and easy to understand. The offset can be accurate to seconds.

Zoneregion (geographic region)

ZoneRegion refers to a geographical region in the format of continent (state, country) / city. The most common regional classification is the time zone database (TZDB).

which defines regions such as' Europe/Paris' and 'Asia/Tokyo'

final class ZoneRegion extends ZoneId implements Serializable {
	...
}

According to the source code, the geographical region ZoneRegion is the inherited implementation class of ZoneId.

However, we found that this is not used externally. The modifier of ZoneRegion is default (which can only be called by classes under the same package). You can only operate through ZoneId.

	@Test
	public void ZoneIdTest7(){
		ZoneId zoneId = ZoneId.systemDefault();
		System.out.println(zoneId);
	}

The blogger is in Xiamen, so the default time zone ID is Asia/Shanghai.

Instances of ZoneId are ZoneOffset or ZoneRegion

ZoneId of(String zoneId, boolean checkAvailable) source code analysis:

/**
     * Parses the ID, taking a flag to indicate whether {@code ZoneRulesException}
     * should be thrown or not, used in deserialization.
     *
     * @param zoneId  the time-zone ID, not null
     * @param checkAvailable  whether to check if the zone ID is available
     * @return the zone ID, not null
     * @throws DateTimeException if the ID format is invalid
     * @throws ZoneRulesException if checking availability and the ID cannot be found
     */
    static ZoneId of(String zoneId, boolean checkAvailable) {
        Objects.requireNonNull(zoneId, "zoneId");
        if (zoneId.length() <= 1 || zoneId.startsWith("+") || zoneId.startsWith("-")) {
            return ZoneOffset.of(zoneId);
        } else if (zoneId.startsWith("UTC") || zoneId.startsWith("GMT")) {
            return ofWithPrefix(zoneId, 3, checkAvailable);
        } else if (zoneId.startsWith("UT")) {
            return ofWithPrefix(zoneId, 2, checkAvailable);
        }
        return ZoneRegion.ofId(zoneId, checkAvailable);
    }


   private static ZoneId ofWithPrefix(String zoneId, int prefixLength, boolean checkAvailable) {
        String prefix = zoneId.substring(0, prefixLength);
        if (zoneId.length() == prefixLength) {
            return ofOffset(prefix, ZoneOffset.UTC);
        }
       ...
    }

From the source code:

  1. zoneId is less than or equal to 1 bit in length, or starts with "+" or "-". ZoneOffset instances are created
  2. Those that start with "UTC", "UT" or "GMT" create ZoneRegion instances
  3. If the above two conditions are not met, the ZoneRegion instance is created
	@Test
	public void ZoneIdTest8(){

		ZoneId zoneId1 = ZoneId.of("+8");
		ZoneId zoneId2 = ZoneId.of("+08:00");
		ZoneId zoneId3 = ZoneId.of("UT+8");
		ZoneId zoneId4 = ZoneId.of("Asia/Shanghai");
		System.out.println();
	}

(2) JSR-310: common date time API

The following describes the date and time APIs commonly used by java8 API, in the order of classes in the java.time package:

  • Clock: clock
  • Instant: instant time.
  • LocalDate: local date. Only indicates month, year and day
  • LocalDateTime: local date time, LocalDate+LocalTime
  • LocalTime: local time; only indicates hours, minutes and seconds
  • OffsetDateTime: date time with time offset (excluding ZoneRegion based time offset)
  • OffsetTime: time with time offset
  • ZonedDateTime: date time with time offset (including time offset based on ZoneRegion)

Bloggers have opened these classes. They all belong to immutable classes. And the official also said that the classes under the java.time package are thread safe.

Clock

Clock class description

public abstract class Clock {
...
}

Clock is an abstract class. It provides four internal classes, which are its internal implementation classes

  • FixedClock: always returns the same instantaneous clock, which is usually used for testing.
  • OffsetClock: offset clock. The unit of time offset is Duration.
  • SystemClock: the default local clock of the system.
  • TickClock: offset clock. The unit of time offset is nanosecond.

Clock provides the following common methods (these methods have corresponding implementations in the implementation class):

// Gets the current Instant object of the clock.
public abstract Instant instant()

// Gets the current millisecond value of the clock
public long millis()

// Gets the time zone used to create the clock.
public abstract ZoneId	getZone()

// Returns a new instance of the current clock with the specified time zone
public abstract Clock withZone(ZoneId zone)

FixedClock

Clock.fixed

public static Clock fixed(Instant fixedInstant, ZoneId zone)

You need to pass instant and zone and return a clock with a fixed instant.

		Instant instant = Instant.now();
		Clock fixedClock = Clock.fixed(instant, ZoneId.of("Asia/Shanghai"));
		Clock fixedClock1 = Clock.fixed(instant, ZoneId.of("GMT"));
		System.out.println("Chinese time zone Clock: "+fixedClock);
		System.out.println("GMT Time zone Clock:"+fixedClock1);

It can be seen from the running results that the returned result has a corresponding time zone.

Verify that the acquired clock changes:

		Clock clock = Clock.systemDefaultZone();
		Clock fixedClock = Clock.fixed(clock.instant(), ZoneId.of("Asia/Shanghai"));
		System.out.println(fixedClock.instant());
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(fixedClock.instant());

Clock.fixed creates a fixed clock, and the clock object will always provide the same time as specified.. As shown in the figure, forced sleep for 1 second, but the time has not changed.

Clock.fixed is better matched with the Offset method

It can be seen from the above that Clock.fixed obtains a fixed clock, and the Offset method is used to add or subtract time

The example code is as follows

		Clock clock = Clock.systemDefaultZone();
		Clock fixedClock = Clock.fixed(clock.instant(), ZoneId.of("Asia/Shanghai"));
		System.out.println(fixedClock.instant());
		Clock clockAdd = Clock.offset(clock, Duration.ofMinutes(20));
		Clock clockSub = Clock.offset(clock, Duration.ofMinutes(-10));
		System.out.println("Original: " + clock.instant());
		System.out.println("Added 20 minutes: " + clockAdd.instant());
		System.out.println("Ten minutes: " + clockSub.instant());

OffsetClock

OffsetClock is the offset clock, and the unit of time offset is Duration.

//Clock
     public static Clock offset(Clock baseClock, Duration offsetDuration) {
        Objects.requireNonNull(baseClock, "baseClock");
        Objects.requireNonNull(offsetDuration, "offsetDuration");
        if (offsetDuration.equals(Duration.ZERO)) {
            return baseClock;
        }
        return new OffsetClock(baseClock, offsetDuration);
    }

It can be seen from the source code that the OffsetClock instance object is returned by using the Clock.offset method

		Clock clock = Clock.systemDefaultZone();
		Clock fixedClock = Clock.fixed(clock.instant(), ZoneId.of("Asia/Shanghai"));
		System.out.println(fixedClock.instant());
		Clock clockAdd = Clock.offset(clock, Duration.ofMinutes(20));
		System.out.println("Original: " + clock.instant());
		System.out.println("Added 20 minutes: " + clockAdd.instant());

SystemClock

SystemClock is the default local clock of the system.

		Clock clock = Clock.systemDefaultZone();
		System.out.println(clock.millis());
		Clock utc = Clock.systemUTC();
		System.out.println(utc.millis());
		System.out.println(System.currentTimeMillis());

It's exactly the same. This depends on the source code

Clock.systemDefaultZone()

The system default time zone ZoneId.systemDefault() is used

    public static Clock systemDefaultZone() {
        return new SystemClock(ZoneId.systemDefault());
    }

Finally, System.currentTimeMillis() is called

Clock.systemUTC()

The UTC time zone ZoneOffset.UTC is used

    public static Clock systemUTC() {
        return new SystemClock(ZoneOffset.UTC);
    }

Finally, System.currentTimeMillis() is called

conclusion

The millis() timestamp obtained by Clock.systemDefaultZone() and Clock.systemUTC() are the same, which is the difference between the corresponding time zones.

TickClock

TickClock is an offset clock, and the minimum unit of time offset is nanoseconds.

As shown in the figure, Clock mainly provides the following three methods

//The timing unit of the constructed clock is a custom offset unit
public static Clock tick(Clock baseClock, Duration tickDuration);
 //The timing unit of the constructed clock is minutes
 public static Clock tickMinutes(ZoneId zone);
//The timing unit of the constructed clock is seconds
public static Clock tickSeconds(ZoneId zone) ;

Actual combat:

		Clock tickClock = Clock.tick(Clock.systemDefaultZone(),Duration.ofHours(1L));
		Clock tickMinutes = Clock.tickMinutes(ZoneId.of("Asia/Shanghai"));
		Clock tickSeconds = Clock.tickSeconds(ZoneId.of("Asia/Shanghai"));

		LocalDateTime tickClockLocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(tickClock.millis()),ZoneId.of("Asia/Shanghai"));
		LocalDateTime tickMinutesLocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(tickMinutes.millis()),ZoneId.of("Asia/Shanghai"));
		LocalDateTime tickSecondsLocalDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(tickSeconds.millis()),ZoneId.of("Asia/Shanghai"));

		System.out.println("tickClock  :"+tickClock.millis() +" Turn into date Time:"+tickClockLocalDateTime);
		System.out.println("tickMinutes:"+tickMinutes.millis() +" Turn into date Time:"+tickMinutesLocalDateTime);
		System.out.println("tickSeconds:"+tickSeconds.millis() +" Turn into date Time:"+tickSecondsLocalDateTime);

The offset unit supports: day, hour, minute, second, haos, nanosecond

Instant

Instant class description

public final class Instant
        implements Temporal, TemporalAdjuster, Comparable<Instant>, Serializable {
        ...
        }

Instant represents the instantaneous time. It is also immutable and thread safe. In fact, the Java.time package is thread safe.

Instant is a new feature in java 8, which has two core fields

	...	
	private final long seconds;
    
    private final int nanos;
	...

One is a timestamp in seconds, and the other is a timestamp in nanoseconds.

Is it very similar to the long timestamp returned by * * System.currentTimeMillis() * * System.currentTimeMillis() returns milliseconds, and Instant has more accurate nanosecond timestamps.

Common usage of Instant

 		Instant now = Instant.now();
		System.out.println("now:"+now);
		System.out.println(now.getEpochSecond()); // second
		System.out.println(now.toEpochMilli()); // millisecond

Instant does not have a time zone, but it can be converted to ZonedDateTime after adding the time zone

		Instant ins = Instant.now();
		ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());
		System.out.println(zdt);

long timestamp to Instant

Pay attention to the time unit of long timestamp. Select the conversion method corresponding to Instant

//1626796436 is a second timestamp
Instant ins = Instant.ofEpochSecond(1626796436);
ZonedDateTime zdt = ins.atZone(ZoneId.systemDefault());
System.out.println("Second timestamp conversion:"+zdt);
//1626796436111l is a second timestamp
Instant ins1 = Instant.ofEpochMilli(1626796436111l);
ZonedDateTime zdt1 = ins1.atZone(ZoneId.systemDefault());
System.out.println("Millisecond timestamp conversion:"+zdt1);

Instant pit

The time obtained by Instant.now() differs from Beijing time by 8 time zones, which is a detail and should be avoided.

Look at the source code, using UTC time.

public static Instant now() {
        return Clock.systemUTC().instant();
    }

Solution:

Instant now = Instant.now().plusMillis(TimeUnit.HOURS.toMillis(8));
System.out.println("now:"+now);

LocalDate

LocalDate class description

LocalDate represents the local date. Only indicates month, year and day. Equivalent to: yyyy mm DD.

Common usage of LocalDate

Get current date

		LocalDate localDate1 = LocalDate.now();
		LocalDate localDate2 = LocalDate.now(ZoneId.of("Asia/Shanghai"));
		LocalDate localDate3 = LocalDate.now(Clock.systemUTC());

		System.out.println("now         :"+localDate1);
		System.out.println("now by zone :"+localDate2);
		System.out.println("now by Clock:"+localDate3);

Get localDate object

		LocalDate localDate1 = LocalDate.of(2021, 8, 14);
		LocalDate localDate2 = LocalDate.parse("2021-08-14");
		System.out.println(localDate1);
		System.out.println(localDate2);

Gets the month, year, and day of the specified date

		LocalDate localDate1 = LocalDate.of(2021, 8, 14);
		// Current date year: 2021
		System.out.println(localDate1.getYear());
		// Current date month object: AUGUST
		System.out.println(localDate1.getMonth());
		// Current date month: August
		System.out.println(localDate1.getMonthValue());
		// The date is the day of the current week: 6
		System.out.println(localDate1.getDayOfWeek().getValue());
		// The date is the day of the current month: 14
		System.out.println(localDate1.getDayOfMonth());
		// The date is the day of the current year: 226
		System.out.println(localDate1.getDayOfYear());

Modification date

		LocalDate localDate1 = LocalDate.of(2021, 8, 14);
		// Year of modifying this date: August 14, 2022
		System.out.println(localDate1.withYear(2022));
		// Month to modify this date: December 14, 2021
		System.out.println(localDate1.withMonth(12));
		// Modify the number of days of this date in the current month: 2021-08-01
		System.out.println(localDate1.withDayOfMonth(1));

Comparison date

		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)));

LocalDate and String are converted to each other, and Date and LocalDate are converted to each other

LocalDate and String are converted to each other
		LocalDate localDate1 = LocalDate.of(2021, 8, 14);
		// LocalDate to String
		DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		String dateString = localDate1.format(dateTimeFormatter);
		System.out.println("LocalDate turn String:"+dateString);
		// String to LocalDate
		String str = "2021-08-14";
		DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		LocalDate date = LocalDate.parse(str, fmt);
		System.out.println("String turn LocalDate:"+date);

Date and LocalDate are converted to each other
	// Date to LocalDate
		Date now = new Date();
		// First convert Date to ZonedDateTime
		Instant instant = now.toInstant();
		ZonedDateTime zonedDateTime = instant.atZone(ZoneId.of("Asia/Shanghai"));
		LocalDate localDate = zonedDateTime.toLocalDate();
		// Sat Aug 14 23:16:28 CST 2021
		System.out.println(now);
		// 2021-08-14
		System.out.println(localDate);

		// LocalDate to Date
		LocalDate now1 = LocalDate.now();
		ZonedDateTime dateTime = now1.atStartOfDay(ZoneId.of("Asia/Shanghai"));
		Date date1 = Date.from(dateTime.toInstant());
		System.out.println(date1);

LocalDateTime

LocalDateTime class description

Represents the current date and time, equivalent to: yyyy mm ddthh: mm: SS

Common usage of LocalDateTime

Get current date and time

		LocalDate d = LocalDate.now(); // current date
		LocalTime t = LocalTime.now(); // current time 
		LocalDateTime dt = LocalDateTime.now(); // Current date and time
		System.out.println(d); // Print in strict accordance with ISO 8601 format
		System.out.println(t); // Print in strict accordance with ISO 8601 format
		System.out.println(dt); // Print in strict accordance with ISO 8601 format

The running result is feasible. The local date and time obtained through now() is always returned in the current default time zone

Gets the specified date and time

		LocalDate d2 = LocalDate.of(2021, 07, 14); // July 14, 2021, note that July = July
		LocalTime t2 = LocalTime.of(13, 14, 20); // 13:14:20
		LocalDateTime dt2 = LocalDateTime.of(2021, 07, 14, 13, 14, 20);
		LocalDateTime dt3 = LocalDateTime.of(d2, t2);
		System.out.println("Specify date and time:"+dt2);
		System.out.println("Specify date and time:"+dt3);

Addition, subtraction and modification of date and time

		LocalDateTime currentTime = LocalDateTime.now(); // Current date and time
		System.out.println("------------------Addition and subtraction of time and its modification-----------------------");
		//3. The addition and subtraction method of localdatetime includes all additions and subtractions of LocalDate and LocalTime. As mentioned above, only a brief introduction is given here
		System.out.println("3.Current time:" + currentTime);
		System.out.println("3.Current time plus 5 years:" + currentTime.plusYears(5));
		System.out.println("3.Current time plus 2 months:" + currentTime.plusMonths(2));
		System.out.println("3.Current time minus 2 days:" + currentTime.minusDays(2));
		System.out.println("3.Current time minus 5 hours:" + currentTime.minusHours(5));
		System.out.println("3.Current time plus 5 minutes:" + currentTime.plusMinutes(5));
		System.out.println("3.Current time plus 20 seconds:" + currentTime.plusSeconds(20));
		//It can also be used flexibly, such as adding one year back, subtracting one day forward, adding two hours back and subtracting five minutes forward
		System.out.println("3.Simultaneous modification(Add one year backward, one day forward, two hours backward and five minutes forward): " + currentTime.plusYears(1).minusDays(1).plusHours(2).minusMinutes(5));
		System.out.println("3.The revised year is 2025:" + currentTime.withYear(2025));
		System.out.println("3.Revised to December:" + currentTime.withMonth(12));
		System.out.println("3.The revision date is 27th:" + currentTime.withDayOfMonth(27));
		System.out.println("3.Modify the hour to 12:" + currentTime.withHour(12));
		System.out.println("3.Modify the minutes to 12:" + currentTime.withMinute(12));
		System.out.println("3.Modify the second to 12:" + currentTime.withSecond(12));

LocalDateTime and Date are converted to each other

Date to LocalDateTime

		System.out.println("------------------Method 1: write step by step-----------------------");
		//Instantiate a time object
		Date date = new Date();
		//Returns a moment representing the same point on the timeline as a date object
		Instant instant = date.toInstant();
		//Get the system default time zone
		ZoneId zoneId = ZoneId.systemDefault();
		//Get the date and time with time zone according to the time zone
		ZonedDateTime zonedDateTime = instant.atZone(zoneId);
		//Convert to LocalDateTime
		LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
		System.out.println("Method 1: Original Date = " + date);
		System.out.println("Method 1: transformed LocalDateTime = " + localDateTime);

		System.out.println("------------------Method 2: one step in place (recommended)-----------------------");
		//Instantiate a time object
		Date todayDate = new Date();
		//Instant.ofepochmili (long l) uses milliseconds in the era of 1970-01-01T00:00:00Z to obtain an instance of instant
		LocalDateTime ldt = Instant.ofEpochMilli(todayDate.getTime()).atZone(ZoneId.systemDefault()).toLocalDateTime();
		System.out.println("Method 2: Original Date = " + todayDate);
		System.out.println("Method 2: transformed LocalDateTime = " + ldt);

LocalDateTime to Date

		System.out.println("------------------Method 1: write step by step-----------------------");
		//Gets the LocalDateTime object and the current time
		LocalDateTime localDateTime = LocalDateTime.now();
		//Get the system default time zone
		ZoneId zoneId = ZoneId.systemDefault();
		//Get the date and time with time zone according to the time zone
		ZonedDateTime zonedDateTime = localDateTime.atZone(zoneId);
		//Returns a moment representing the same point on the timeline as a date object
		Instant instant = zonedDateTime.toInstant();
		//Convert to Date
		Date date = Date.from(instant);
		System.out.println("Method 1: Original LocalDateTime = " + localDateTime);
		System.out.println("Method 1: transformed Date = " + date);

		System.out.println("------------------Method 2: one step in place (recommended)-----------------------");
		//Instantiate a LocalDateTime object
		LocalDateTime now = LocalDateTime.now();
		//Convert to date
		Date dateResult = Date.from(now.atZone(ZoneId.systemDefault()).toInstant());
		System.out.println("Method 2: Original LocalDateTime = " + now);
		System.out.println("Method 2: transformed Date = " + dateResult);

LocalTime

LocalTime class description

LocalTime: local time; only indicates hours, minutes and seconds

Common usage of LocalTime

Get current time

		LocalTime localTime1 = LocalTime.now();
		LocalTime localTime2 = LocalTime.now(ZoneId.of("Asia/Shanghai"));
		LocalTime localTime3 = LocalTime.now(Clock.systemDefaultZone());

		System.out.println("now         :"+localTime1);
		System.out.println("now by zone :"+localTime2);
		System.out.println("now by Clock:"+localTime3);

Get LocalTime object

		LocalTime localTime1 = LocalTime.of(23, 26, 30);
		LocalTime localTime2 = LocalTime.of(23, 26);
		System.out.println(localTime1);
		System.out.println(localTime2);

Gets the hour, minute, and second of the specified date

		LocalTime localTime1 = LocalTime.of(23, 26, 30);
		//Hour of current time: 23
		System.out.println(localTime1.getHour());
		//Minute of current time: 26
		System.out.println(localTime1.getMinute());
		//Seconds of current time: 30
		System.out.println(localTime1.getSecond());

Modify hours, minutes and seconds

		LocalTime localTime1 = LocalTime.of(23, 26, 30);
		//Time of modification: 00:26:30
		System.out.println(localTime1.withHour(0));
		//Modification time: 23:30:30
		System.out.println(localTime1.withMinute(30));
		//Second of modification time: 23:26:59
		System.out.println(localTime1.withSecond(59));

Comparison time

		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)));

OffsetDateTime

OffsetDateTime class description

OffsetDateTime: date time with time offset (excluding ZoneRegion based time offset)

public final class OffsetDateTime
        implements Temporal, TemporalAdjuster, Comparable<OffsetDateTime>, Serializable {
    //The minimum supported {@code OffsetDateTime}, '-999999999-01-01T00:00:00+18:00' 
    public static final OffsetDateTime MIN = LocalDateTime.MIN.atOffset(ZoneOffset.MAX);
    // The maximum supported {@code OffsetDateTime}, '+999999999-12-31T23:59:59.999999999-18:00'.
    public static final OffsetDateTime MAX = LocalDateTime.MAX.atOffset(ZoneOffset.MIN);
        ...
        }

MIN and MAX above are public static variables.

Common usage of OffsetDateTime

Get current date and time

		OffsetDateTime offsetDateTime1 = OffsetDateTime.now();
		OffsetDateTime offsetDateTime2 = OffsetDateTime.now(ZoneId.of("Asia/Shanghai"));
		OffsetDateTime offsetDateTime3 = OffsetDateTime.now(Clock.systemUTC());

		System.out.println("now         :"+offsetDateTime1);
		System.out.println("now by zone :"+offsetDateTime2);
		System.out.println("now by Clock:"+offsetDateTime3);

Gets the OffsetDateTime object

		LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20);
		OffsetDateTime offsetDateTime1 = OffsetDateTime.of(localDateTime1, ZoneOffset.ofHours(8));
		OffsetDateTime offsetDateTime2 = OffsetDateTime. of(2021, 8, 15, 13, 14, 20,0, ZoneOffset.ofHours(8));
		Instant now = Instant.now();
		OffsetDateTime offsetDateTime3 = OffsetDateTime.ofInstant(now, ZoneId.of("Asia/Shanghai"));

		System.out.println(offsetDateTime1);
		System.out.println(offsetDateTime2);
		System.out.println(offsetDateTime3);

Gets the year, day, hour, minute and second of the specified date

		LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20);
		OffsetDateTime offsetDateTime1 = OffsetDateTime.of(localDateTime1, ZoneOffset.ofHours(8));
		//Year of current time: 2021
		System.out.println(offsetDateTime1.getYear());
		//Month of current time: 8
		System.out.println(offsetDateTime1.getMonthValue());
		//Day of current time: 15
		System.out.println(offsetDateTime1.getDayOfMonth());
		//Hour of current time: 13
		System.out.println(offsetDateTime1.getHour());
		//Minute of current time: 14
		System.out.println(offsetDateTime1.getMinute());
		//Seconds of current time: 20
		System.out.println(offsetDateTime1.getSecond());

Modify month, day, hour, minute and second

		LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20);
		OffsetDateTime offsetDateTime1 = OffsetDateTime.of(localDateTime1, ZoneOffset.ofHours(8));
		//Year of revision: 2022-08-15T13:14:20+08:00
		System.out.println(offsetDateTime1.withYear(2022));
		//Month of modification time: 2021-09-15T13:14:20+08:00
		System.out.println(offsetDateTime1.withMonth(9));
		//Date of modification: 2021-08-30T13:14:20+08:00
		System.out.println(offsetDateTime1.withDayOfMonth(30));
		//Modification time: 2021-08-15T00:14:20+08:00
		System.out.println(offsetDateTime1.withHour(0));
		//Modification time: 2021-08-15T13:30:20+08:00
		System.out.println(offsetDateTime1.withMinute(30));
		//Second of modification time: 2021-08-15T13:14:59+08:00
		System.out.println(offsetDateTime1.withSecond(59));

Compare date and time

		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));

Convert string to OffsetDateTime object

				String str = "2021-08-15T10:15:30+08:00";
		OffsetDateTime offsetDateTime1 = OffsetDateTime.parse(str);
		OffsetDateTime offsetDateTime2 = OffsetDateTime.parse(str,DateTimeFormatter.ISO_OFFSET_DATE_TIME);

		System.out.println(offsetDateTime1);
		System.out.println(offsetDateTime2);

OffsetTime

OffsetTime class description

OffsetTime: time with time offset

public final class OffsetTime
        implements Temporal, TemporalAdjuster, Comparable<OffsetTime>, Serializable {
   //The minimum supported {@code OffsetTime}, '00:00:00+18:00'.
    public static final OffsetTime MIN = LocalTime.MIN.atOffset(ZoneOffset.MAX);
    
    //The maximum supported {@code OffsetTime}, '23:59:59.999999999-18:00'.
    public static final OffsetTime MAX = LocalTime.MAX.atOffset(ZoneOffset.MIN);
    ...
}

MIN and MAX above are public static variables.

Common usage of OffsetTime

Get current time

		OffsetTime offsetTime1 = OffsetTime.now();
		OffsetTime offsetTime2 = OffsetTime.now(ZoneId.of("Asia/Shanghai"));
		OffsetTime offsetTime3 = OffsetTime.now(Clock.systemUTC());

		System.out.println("now         :"+offsetTime1);
		System.out.println("now by zone :"+offsetTime2);
		System.out.println("now by Clock:"+offsetTime3);

Get OffsetTime object

		LocalTime localTime1 = LocalTime.of(13, 14, 20);
		OffsetTime offsetTime1 = OffsetTime.of(localTime1, ZoneOffset.ofHours(8));
		OffsetTime offsetTime2 = OffsetTime. of(13, 14, 20,0, ZoneOffset.ofHours(8));
		Instant now = Instant.now();
		OffsetTime offsetTime3 = OffsetTime.ofInstant(now, ZoneId.of("Asia/Shanghai"));

		System.out.println(offsetTime1);
		System.out.println(offsetTime2);
		System.out.println(offsetTime3);

Gets the hour, minute, and second of the specified time

		LocalTime localTime1 = LocalTime.of( 13, 14, 20);
		OffsetTime offsetTime1 = OffsetTime.of(localTime1, ZoneOffset.ofHours(8));

		//Hour of current time: 13
		System.out.println(offsetTime1.getHour());
		//Minute of current time: 14
		System.out.println(offsetTime1.getMinute());
		//Seconds of current time: 20
		System.out.println(offsetTime1.getSecond());

Modify hours, minutes and seconds

		LocalTime localTime1 = LocalTime.of( 13, 14, 20);
		OffsetTime offsetTime1 = OffsetTime.of(localTime1, ZoneOffset.ofHours(8));

		//Modification time: 00:14:20 + 08:00
		System.out.println(offsetTime1.withHour(0));
		//Modification time: 13:30:20 + 08:00
		System.out.println(offsetTime1.withMinute(30));
		//Second of modification time: 13:14:59 + 08:00
		System.out.println(offsetTime1.withSecond(59));

Comparison time

		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));

ZonedDateTime

ZonedDateTime class description

Represents a date and time with time zone. ZonedDateTime can be understood as LocalDateTime+ZoneId

As can be seen from the source code, the ZonedDateTime class defines two variables, LocalDateTime and ZoneId.

The ZonedDateTime class is also immutable and thread safe.

public final class ZonedDateTime
        implements Temporal, ChronoZonedDateTime<LocalDate>, Serializable {

    /**
     * Serialization version.
     */
    private static final long serialVersionUID = -6260982410461394882L;

    /**
     * The local date-time.
     */
    private final LocalDateTime dateTime;
    /**
     * The time-zone.
     */
    private final ZoneId zone;
    
    ...
}

Common usage of ZonedDateTime

Get current date and time

		// The default time zone gets the current time
		ZonedDateTime zonedDateTime = ZonedDateTime.now();
		// Use the specified time zone to obtain the current time. Asia/Shanghai is the Shanghai time zone
		ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
		//Withzonesameeinstant is the conversion time zone, and the parameter is ZoneId
		ZonedDateTime zonedDateTime2 = zonedDateTime.withZoneSameInstant(ZoneId.of("America/New_York"));
		System.out.println(zonedDateTime);
		System.out.println(zonedDateTime1);
		System.out.println(zonedDateTime2);

		ZonedDateTime zonedDateTime1 = ZonedDateTime.now();
		ZonedDateTime zonedDateTime2 = ZonedDateTime.now(ZoneId.of("Asia/Shanghai"));
		ZonedDateTime zonedDateTime3 = ZonedDateTime.now(Clock.systemUTC());

		System.out.println("now         :"+zonedDateTime1);
		System.out.println("now by zone :"+zonedDateTime2);
		System.out.println("now by Clock:"+zonedDateTime3);

Get ZonedDateTime object

		LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20);
		ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime1, ZoneOffset.ofHours(8));
		ZonedDateTime zonedDateTime2 = ZonedDateTime. of(2021, 8, 15, 13, 14, 20,0, ZoneOffset.ofHours(8));
		Instant now = Instant.now();
		ZonedDateTime zonedDateTime3 = ZonedDateTime.ofInstant(now, ZoneId.of("Asia/Shanghai"));

		System.out.println(zonedDateTime1);
		System.out.println(zonedDateTime2);
		System.out.println(zonedDateTime3);

Gets the year, day, hour, minute and second of the specified date

		LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20);
		ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime1, ZoneOffset.ofHours(8));
		//Year of current time: 2021
		System.out.println(zonedDateTime1.getYear());
		//Month of current time: 8
		System.out.println(zonedDateTime1.getMonthValue());
		//Day of current time: 15
		System.out.println(zonedDateTime1.getDayOfMonth());
		//Hour of current time: 13
		System.out.println(zonedDateTime1.getHour());
		//Minute of current time: 14
		System.out.println(zonedDateTime1.getMinute());
		//Seconds of current time: 20
		System.out.println(zonedDateTime1.getSecond());

Modify month, day, hour, minute and second

		LocalDateTime localDateTime1 = LocalDateTime.of(2021, 8, 15, 13, 14, 20);
		ZonedDateTime zonedDateTime1 = ZonedDateTime.of(localDateTime1, ZoneOffset.ofHours(8));
		//Year of revision: 2022-08-15T13:14:20+08:00
		System.out.println(zonedDateTime1.withYear(2022));
		//Month of modification time: 2021-09-15T13:14:20+08:00
		System.out.println(zonedDateTime1.withMonth(9));
		//Date of modification: 2021-08-30T13:14:20+08:00
		System.out.println(zonedDateTime1.withDayOfMonth(30));
		//Modification time: 2021-08-15T00:14:20+08:00
		System.out.println(zonedDateTime1.withHour(0));
		//Modification time: 2021-08-15T13:30:20+08:00
		System.out.println(zonedDateTime1.withMinute(30));
		//Second of modification time: 2021-08-15T13:14:59+08:00
		System.out.println(zonedDateTime1.withSecond(59));

Compare date and time

		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));

LocalDateTime+ZoneId becomes ZonedDateTime

		LocalDateTime localDateTime = LocalDateTime.now();
		ZonedDateTime zonedDateTime1 = localDateTime.atZone(ZoneId.systemDefault());
		ZonedDateTime zonedDateTime2 = localDateTime.atZone(ZoneId.of("America/New_York"));
		System.out.println(zonedDateTime1);
		System.out.println(zonedDateTime2);

The above example shows that LocalDateTime can be converted into ZonedDateTime.

(3) JSR-310: formatting and parsing

DateTimeFormatter

DateTimeFormatter class description

DateTimeFormatter is used to format date and time display, and DateTimeFormatter is an immutable class and thread safe.

public final class DateTimeFormatter {
...
}

When it comes to the formatted display of time, we have to say that the old friend SimpleDateFormat needs to be used before formatting Date. However, we know that SimpleDateFormat is thread unsafe, which is not clear. Please see this article The SimpleDateFormat thread of java is unsafe. There is a problem. Virtual bamboo teaches you a variety of solutions

Common usage of DateTimeFormatter

format

		ZonedDateTime zonedDateTime = ZonedDateTime.now();
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm ZZZZ");
		System.out.println(formatter.format(zonedDateTime));

		DateTimeFormatter usFormatter = DateTimeFormatter.ofPattern("E, MMMM/dd/yyyy HH:mm", Locale.US);
		System.out.println(usFormatter.format(zonedDateTime));

		DateTimeFormatter chinaFormatter = DateTimeFormatter.ofPattern("yyyy MMM dd EE HH:mm", Locale.CHINA);
		System.out.println(chinaFormatter.format(zonedDateTime));

analysis

		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy year MM month dd day HH Time mm branch ss second");
		String dateTime = "2021 August 22, 2013 13:14:20";
		LocalDateTime localDateTime = LocalDateTime.parse(dateTime, formatter);
		System.out.println(localDateTime);

Have you noticed that the parse method is placed in the LocalDateTime class instead of the DateTimeFormatter class. This design is in line with the normal idea. If you want to parse the date and time of LocalDateTime, use LocalDateTime. If you want to parse other date and time objects of JSR-310, use the corresponding date and time object to parse.

Bloggers have read the commonly used date and time API s. Except for Clock (which does not need to be parsed), there are other methods to implement parse.

Pit of DateTimeFormatter

1. In normal configuration, string dates in standard format can be converted normally. If the month, day, hour, minute and second are less than two digits, you need to fill in 0. Otherwise, the conversion will fail and an exception will be thrown.

		DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
		LocalDateTime dt1 = LocalDateTime.parse("2021-7-20 23:46:43.946", DATE_TIME_FORMATTER);
		System.out.println(dt1);

Error will be reported:

java.time.format.DateTimeParseException: Text '2021-7-20 23:46:43.946' could not be parsed at index 5

Analysis reason: the format string does not match the actual time

"yyyy-MM-dd HH:mm:ss.SSS"

"2021-7-20 23:46:43.946"

The middle month format is MM, and the actual time is 7

Solution: keep the format string matching the actual time

	DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
		LocalDateTime dt1 = LocalDateTime.parse("2021-07-20 23:46:43.946", DATE_TIME_FORMATTER);
		System.out.println(dt1);

2. YYYY and DD are used with caution

		LocalDate date = LocalDate.of(2020,12,31);
		DateTimeFormatter formatter = DateTimeFormatter.ofPattern("YYYYMM");
		// The result is 202112
		System.out.println( formatter.format(date));

Java's DateTimeFormatter pattern "YYYY" gives you the week-based-year, (by default, ISO-8601 standard) the year of the Thursday of that week.

YYYY is the year of the current week, and the week based year is specified in ISO 8601. December 31, 2020, the weekly year, is 2021

 private static void tryit(int Y, int M, int D, String pat) {
        DateTimeFormatter fmt = DateTimeFormatter.ofPattern(pat);
        LocalDate         dat = LocalDate.of(Y,M,D);
        String            str = fmt.format(dat);
        System.out.printf("Y=%04d M=%02d D=%02d " +
            "formatted with " +
            "\"%s\" -> %s\n",Y,M,D,pat,str);
    }
    public static void main(String[] args){
        tryit(2020,01,20,"MM/DD/YYYY");
        tryit(2020,01,21,"DD/MM/YYYY");
        tryit(2020,01,22,"YYYY-MM-DD");
        tryit(2020,03,17,"MM/DD/YYYY");
        tryit(2020,03,18,"DD/MM/YYYY");
        tryit(2020,03,19,"YYYY-MM-DD");
    }
Y=2020 M=01 D=20 formatted with "MM/DD/YYYY" -> 01/20/2020
Y=2020 M=01 D=21 formatted with "DD/MM/YYYY" -> 21/01/2020
Y=2020 M=01 D=22 formatted with "YYYY-MM-DD" -> 2020-01-22
Y=2020 M=03 D=17 formatted with "MM/DD/YYYY" -> 03/77/2020
Y=2020 M=03 D=18 formatted with "DD/MM/YYYY" -> 78/03/2020
Y=2020 M=03 D=19 formatted with "YYYY-MM-DD" -> 2020-03-79

The last three dates are problematic, because the capitalized DD represents the day of the year, not the day of the month, but DD is no problem.

Examples refer to: https://www.cnblogs.com/tonyY/p/12153335.html

Therefore, yyyy and dd are recommended.

3. DateTimeFormatter.format(Instant) will report an error

Error message:
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: YearOfEra
Analysis reason:

How is the code * * DateTimeFormatter.format(Instant) * * handled?

    public String format(TemporalAccessor temporal) {
        StringBuilder buf = new StringBuilder(32);
        formatTo(temporal, buf);
        return buf.toString();
    }


First, a new StringBuilder object is created to splice strings;

Then call **formatTo(temporal, buf) * method.

public void formatTo(TemporalAccessor temporal, Appendable appendable) {
    Objects.requireNonNull(temporal, "temporal");
    Objects.requireNonNull(appendable, "appendable");
    try {
        DateTimePrintContext context = new DateTimePrintContext(temporal, this);
        if (appendable instanceof StringBuilder) {
            printerParser.format(context, (StringBuilder) appendable);
        } else {
            // buffer output to avoid writing to appendable in case of error
            StringBuilder buf = new StringBuilder(32);
            printerParser.format(context, buf);
            appendable.append(buf);
        }
    } catch (IOException ex) {
        throw new DateTimeException(ex.getMessage(), ex);
    }
}

**The formatto (temporary, buf) * * method also judges that the two input parameters are null first.

Then, the Instant object is encapsulated in a new DateTimePrintContext object

If there is a problem running the demo, check it

		//Format the date according to a specific format
		DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
		String dateStr = DateUtil.format(new Date(),dtf);
		System.out.println(dateStr);

Here is the source code of jdk. DateTimeFormatter.format

As can be seen from the above, numberprinterparser. Format() will be called. Numberprinterparser is in the DateTimeFormatterBuilder class.

An error will be reported at this step

Why are errors reported? Let's look at what happened to context.getValue(field):

From the above code, temporary is actually an Instant object, and Instant.getLong only supports four field types..

NANO_OF_SECOND
MICRO_OF_SECOND
MILLI_OF_SECOND
INSTANT_SECONDS

If it is not the above field types, an exception is thrown

DateUtil.format when DateTimeFormatter is encountered, it will first convert the Date object to Instant. Because of the lack of time zone, an error will be reported.

Solution:
/**
 * Format the date according to a specific format
 *
 * @param date   Formatted date
 * @param format
 * @return Formatted string
 * @since 5.0.0
 */
public static String format(Date date, DateTimeFormatter format) {
   if (null == format || null == date) {
      return null;
   }
   Instant instant = date.toInstant();
   ZonedDateTime zonedDateTime = instant.atZone(ZoneId.systemDefault());
   LocalDateTime localDateTime = zonedDateTime.toLocalDateTime();
   return format.format(localDateTime);
}

First convert the date type to the LocalDateTime type, and then format the DateTimeFormatter.format(LocalDateTime)

Test demo

//Format the date according to a specific format
String str = "2021-07-25 20:11:25";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:dd");
Date date = DateUtil.parse(str);
String dateStr = DateUtil.format(date,dtf);
System.out.println(dateStr);
Assert.assertEquals(str, dateStr);

DateTimeFormatterBuilder

DateTimeFormatterBuilder class description

All formatters for DateTimeFormatter are created using the DateTimeFormatterBuilder builder class.

Look at the following two ofPattern source codes:

//DateTimeFormatter
public static DateTimeFormatter ofPattern(String pattern) {
        return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter();
    }
    
     public static DateTimeFormatter ofPattern(String pattern, Locale locale) {
        return new DateTimeFormatterBuilder().appendPattern(pattern).toFormatter(locale);
    }

Parsing style configuration

Four parsing style configurations are officially provided. The SettingsParser is enumerated as follows:

 static enum SettingsParser implements DateTimePrinterParser {
     // Case sensitive
        SENSITIVE,
     // Case insensitive
        INSENSITIVE,
     //strict
        STRICT,
     //easy
        LENIENT;
        ...
        }

Corresponding methods in DateTimeFormatterBuilder class:

// Case sensitive
public DateTimeFormatterBuilder parseCaseSensitive()
// Case insensitive
public DateTimeFormatterBuilder parseCaseInsensitive()
// strict
public DateTimeFormatterBuilder parseStrict()
// easy
public DateTimeFormatterBuilder parseLenient()

The corresponding source codes of the four methods are as follows:

// Case sensitive
public DateTimeFormatterBuilder parseCaseSensitive() {
        appendInternal(SettingsParser.SENSITIVE);
        return this;
    }
// Case insensitive
 public DateTimeFormatterBuilder parseCaseInsensitive() {
        appendInternal(SettingsParser.INSENSITIVE);
        return this;
    }
// strict
 public DateTimeFormatterBuilder parseStrict() {
        appendInternal(SettingsParser.STRICT);
        return this;
    }
// easy
public DateTimeFormatterBuilder parseLenient() {
        appendInternal(SettingsParser.LENIENT);
        return this;
    }

As you can see, they all call the appendInternal method.

Next, look at the appendInternal source code:

 private int appendInternal(DateTimePrinterParser pp) {
        Objects.requireNonNull(pp, "pp");
        if (active.padNextWidth > 0) {
            if (pp != null) {
                pp = new PadPrinterParserDecorator(pp, active.padNextWidth, active.padNextChar);
            }
            active.padNextWidth = 0;
            active.padNextChar = 0;
        }
        active.printerParsers.add(pp);
        active.valueParserIndex = -1;
        return active.printerParsers.size() - 1;
    }

active is a DateTimeFormatterBuilder instance, and the DateTimeFormatterBuilder instance has a list list < DateTimePrinterParser >. After reading the source code, we can see that the real parsing work is done by the corresponding instance of DateTimePrinterParser.

Source code of DateTimePrinterParser:

 interface DateTimePrinterParser {

        boolean format(DateTimePrintContext context, StringBuilder buf);

        int parse(DateTimeParseContext context, CharSequence text, int position);
    }

There are 16 instances of DateTimePrinterParser in the source code.

//1.Composite printer and parser.
static final class CompositePrinterParser implements DateTimePrinterParser {...}

//2.Pads the output to a fixed width.
static final class PadPrinterParserDecorator implements DateTimePrinterParser {...}

//3.Enumeration to apply simple parse settings.
static enum SettingsParser implements DateTimePrinterParser{...}

//4. Defaults a value into the parse if not currently present.
static class DefaultValueParser implements DateTimePrinterParser {...}

//5.Prints or parses a character literal.
static final class CharLiteralPrinterParser implements DateTimePrinterParser {...}

//6.Prints or parses a string literal.
static final class StringLiteralPrinterParser implements DateTimePrinterParser {...}

//7.Prints and parses a numeric date-time field with optional padding.
static class NumberPrinterParser implements DateTimePrinterParser {...}

//8.Prints and parses a numeric date-time field with optional padding.
static final class FractionPrinterParser implements DateTimePrinterParser {...}

//9.Prints or parses field text.
static final class TextPrinterParser implements DateTimePrinterParser  {...}

//10.Prints or parses an ISO-8601 instant.
static final class InstantPrinterParser implements DateTimePrinterParser  {...}

//11.Prints or parses an offset ID.
static final class OffsetIdPrinterParser implements DateTimePrinterParser   {...}

//12.Prints or parses an offset ID.
static final class LocalizedOffsetIdPrinterParser implements DateTimePrinterParser {...}

//13.Prints or parses a zone ID.
static class ZoneIdPrinterParser implements DateTimePrinterParser {...}

//14. Prints or parses a chronology.
 static final class ChronoPrinterParser implements DateTimePrinterParser {...}

//15.Prints or parses a localized pattern.
static final class LocalizedPrinterParser implements DateTimePrinterParser {...}

//16.Prints or parses a localized pattern from a localized field.
 static final class WeekBasedFieldPrinterParser implements DateTimePrinterParser {...}

(4) JSR-310: common calculation tools

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.

TemporalAdjuster date calibrator

Serial numbermethoddescribe
1dayOfWeekInMonthReturns the day ordinal of the week in the same month
2firstDayOfMonthReturns the first day of the month
3firstDayOfNextMonthReturn to the first day of next month
4firstDayOfNextYearReturn to the first day of the next year
5firstDayOfYearReturn to the first day of the year
6firstInMonthReturns the first day of the week in the same month
7lastDayOfMonthReturns the last day of the month
8lastDayOfNextMonthReturn to the last day of next month
9lastDayOfNextYearReturn to the last day of the next year
0lastDayOfYearReturn to the last day of the year
11lastInMonthReturns the last day of the week in the same month
12next / previousReturns the given day of the week after / before
13nextOrSame / previousOrSameReturns the last / previous given day of the week. If this value meets the conditions, it will be returned directly
LocalDateTime now = LocalDateTime.of(2021,9,8,0,20,13);
		System.out.println("Current time:" + now + "======>" + now.getDayOfWeek());
		System.out.println("Next Monday:" + now.with(TemporalAdjusters.next(DayOfWeek.MONDAY)));
		System.out.println("Last Monday:" + now.with(TemporalAdjusters.previous(DayOfWeek.MONDAY)));
		System.out.println("Next Friday:" + now.with(TemporalAdjusters.nextOrSame(DayOfWeek.FRIDAY)));
		System.out.println("Last Friday:" + now.with(TemporalAdjusters.previousOrSame(DayOfWeek.FRIDAY)));
		System.out.println("Last Friday of the month:" + now.with(TemporalAdjusters.lastInMonth(DayOfWeek.FRIDAY)));
		System.out.println("The first Friday of this month:" + now.with(TemporalAdjusters.firstInMonth(DayOfWeek.FRIDAY)));
		System.out.println("First day of the month:" + now.with(TemporalAdjusters.firstDayOfMonth()));
		System.out.println("Last day of the month:" + now.with(TemporalAdjusters.lastDayOfMonth()));
		System.out.println("First day of next month:" + now.with(TemporalAdjusters.firstDayOfNextMonth()));
		System.out.println("First day of the year:" + now.with(TemporalAdjusters.firstDayOfYear()));
		System.out.println("Last day of the year:" + now.with(TemporalAdjusters.lastDayOfYear()));
		System.out.println("The first day of the following year:" + now.with(TemporalAdjusters.firstDayOfNextYear()));
		System.out.println("The second Friday of the month:" + now.with(TemporalAdjusters.dayOfWeekInMonth(2,DayOfWeek.FRIDAY)));
		System.out.println("Two weeks later:" + now.with(TemporalAdjusters.ofDateAdjuster(date -> date.plusWeeks(2))));

(5) JSR-310: actual combat + source code analysis

Usage scenario

Encapsulate the date and time tool class in JDK8 +

Project reference

The basis of this blog post: hutool-5.6.5 version source code

        <dependency>
			<groupId>cn.hutool</groupId>
			<artifactId>hutool-core</artifactId>
			<version>5.6.5</version>
		</dependency>

Method summary

methoddescribe
cn.hutool.core.date.LocalDateTimeUtil.now()
Current time, default time zone
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant)
{@ link Instant} to {@ link LocalDateTime}, using the default time zone
cn.hutool.core.date.LocalDateTimeUtil.ofUTC(java.time.Instant)
{@ link Instant} to {@ link LocalDateTime}, using UTC time zone
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.ZonedDateTime)
{@ link ZonedDateTime} to {@ link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.time.ZoneId)
{@ link Instant} to {@ link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.util.TimeZone)
{@ link Instant} to {@ link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.of(long)
Milliseconds to {@ link LocalDateTime}, using the default time zone

Note: this method uses the default time zone. If it is not UTC, it will produce a time offset

cn.hutool.core.date.LocalDateTimeUtil.ofUTC(long)
MS to {@ link LocalDateTime}, using UTC time zone
cn.hutool.core.date.LocalDateTimeUtil.of(long, java.time.ZoneId)
Milliseconds to {@ link LocalDateTime}. Depending on the time zone, the result will have a time offset
cn.hutool.core.date.LocalDateTimeUtil.of(long, java.util.TimeZone)
Milliseconds to {@ link LocalDateTime}, resulting in a time offset
cn.hutool.core.date.LocalDateTimeUtil.of(java.util.Date)
{@ link Date} to {@ link LocalDateTime}, using the default time zone
cn.hutool.core.date.LocalDateTimeUtil.of(java.time.temporal.TemporalAccessor)
{@ link TemporalAccessor} go to {@ link LocalDateTime} and use the default time zone
cn.hutool.core.date.LocalDateTimeUtil.ofDate(java.time.temporal.TemporalAccessor)
{@ link TemporalAccessor} to {@ link LocalDate}, using the default time zone
cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence)
The parsed date time string is {@ link LocalDateTime}. Only yyyy MM DD'T 'HH:mm:ss format is supported, for example: 2007-12-03T10:15:30
cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)
The parsed date time string is {@ link LocalDateTime}. The format supports date time, date and time
cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.lang.String)
Resolve the date time string to {@ link LocalDateTime}
cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence)
The parsed date and time string is {@ link LocalDate}. Only yyyy MM DD'T 'HH:mm:ss format is supported, for example: 2007-12-03T10:15:30
cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.time.format.DateTimeFormatter)
The parsed date time string is {@ link LocalDate}, and the format supports date
cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.lang.String)
Parse date string as {@ link LocalDate}
cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDateTime)
Format the date and time in yyyy MM DD HH: mm: SS format
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.time.format.DateTimeFormatter)
Format the date and time in the specified format
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.lang.String)
Format the date and time in the specified format
cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDate)
Format the date and time in yyyy MM DD format
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.time.format.DateTimeFormatter)
Format the date and time in the specified format
cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.lang.String)
Format the date and time in the specified format
cn.hutool.core.date.LocalDateTimeUtil.offset(java.time.LocalDateTime, long, java.time.temporal.TemporalUnit)
Date offset: add different values according to different field s (offset will modify the incoming objects)
cn.hutool.core.date.LocalDateTimeUtil.between(java.time.LocalDateTime, java.time.LocalDateTime)
Gets the difference between two dates. If the end time is earlier than the start time, the result is negative.

The returned result is the {@ link Duration} object, and the phase difference unit is returned by calling the toXXX method

cn.hutool.core.date.LocalDateTimeUtil.between(java.time.LocalDateTime, java.time.LocalDateTime, java.time.temporal.ChronoUnit)
Gets the difference between two dates. If the end time is earlier than the start time, the result is negative.

The return result is a long value of time difference

cn.hutool.core.date.LocalDateTimeUtil.betweenPeriod(java.time.LocalDate, java.time.LocalDate)
Get the apparent time difference between two dates. If the end time is earlier than the start time, the result is negative.

For example, February 1, 2011 and August 11, 2021 differ by 10 days and 6 months respectively

cn.hutool.core.date.LocalDateTimeUtil.beginOfDay(java.time.LocalDateTime)
Modify to the start time of the day, for example: 2020-02-02 00:00:00000
cn.hutool.core.date.LocalDateTimeUtil.endOfDay(java.time.LocalDateTime)
Modify to the end time of the day, for example: 2020-02-02 23:59:59999
cn.hutool.core.date.LocalDateTimeUtil.toEpochMilli(java.time.temporal.TemporalAccessor)
{@ link TemporalAccessor} converted to timestamp (number of milliseconds from 1970-01-01T00:00:00Z)

Method details - now()

Method name: cn.hutool.core.date.LocalDateTimeUtil.now()

Method description

Current time, default time zone

Supported version and above

Parameter Description:

Parameter namedescribe

Return value:

{@link LocalDateTime}

Reference case:

		Assert.assertNotNull(LocalDateTimeUtil.now());
		System.out.println(LocalDateTimeUtil.now());

Source code analysis:

/**
 * Current time, default time zone
 *
 * @return {@link LocalDateTime}
 */
public static LocalDateTime now() {
   return LocalDateTime.now();
}

Source code of LocalDateTime.now()

public static LocalDateTime now() {
    return now(Clock.systemDefaultZone());
}

Clock.systemDefaultZone()

The system default time zone ZoneId.systemDefault() is used

    public static Clock systemDefaultZone() {
        return new SystemClock(ZoneId.systemDefault());
    }

Finally, System.currentTimeMillis() is called

Method details - of(java.time.Instant)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant)

Method description

{@ link Instant} to {@ link LocalDateTime}, using the default time zone

Supported version and above

Parameter Description:

Parameter namedescribe
Instant instant
instant {@link Instant}

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2020-01-23 12:23:56";
		final DateTime dt = DateUtil.parse(dateStr);

		LocalDateTime of = LocalDateTimeUtil.of(dt.toInstant());
		System.out.println(of);

Source code analysis:

public static LocalDateTime of(Instant instant) {
		return of(instant, ZoneId.systemDefault());
	}

The default time zone is used here, so the printed date and time is with time zone.

public static LocalDateTime of(Instant instant, ZoneId zoneId) {
   if (null == instant) {
      return null;
   }
   return LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()));
}

Method details - ofUTC(java.time.Instant)

Method name: cn.hutool.core.date.LocalDateTimeUtil.ofUTC(java.time.Instant)

Method description

{@ link Instant} to {@ link LocalDateTime}, using UTC time zone

Supported version and above

Parameter Description:

Parameter namedescribe
Instant instant
instant {@link Instant}

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2020-01-23T12:23:56";
		final DateTime dt = DateUtil.parse(dateStr);

		LocalDateTime of = LocalDateTimeUtil.ofUTC(dt.toInstant());
		Assert.assertEquals(dateStr, of.toString());
		System.out.println(of);

Source code analysis:

	public static LocalDateTime ofUTC(Instant instant) {
		return of(instant, ZoneId.of("UTC"));
	}

The UTC time zone is used here, and the next LocalDateTime.ofInstant is called.

	public static LocalDateTime of(Instant instant, ZoneId zoneId) {
		if (null == instant) {
			return null;
		}

		return LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()));
	}

Method details - of(java.time.ZonedDateTime)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(java.time.ZonedDateTime)

Method description

{@ link ZonedDateTime} to {@ link LocalDateTime}

Supported version and above

Parameter Description:

Parameter namedescribe
ZonedDateTime zonedDateTime
zonedDateTime {@link ZonedDateTime}

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-21T11:23:56";
		final DateTime dt = DateUtil.parse(dateStr);
		//Use default time zone
		LocalDateTime localDateTime = LocalDateTimeUtil.of(dt);
		System.out.println(localDateTime);
		ZonedDateTime zonedDateTime = localDateTime.atZone(ZoneId.systemDefault());
		System.out.println(zonedDateTime);
		zonedDateTime = localDateTime.atZone( ZoneId.of("Asia/Shanghai"));
		System.out.println(zonedDateTime);
		LocalDateTime of = LocalDateTimeUtil.of(zonedDateTime);

		Assert.assertNotNull(of);
		Assert.assertEquals("2021-05-21T11:23:56", of.toString());

Source code analysis:

public static LocalDateTime of(ZonedDateTime zonedDateTime) {
		if (null == zonedDateTime) {
			return null;
		}
		return zonedDateTime.toLocalDateTime();
	}

Here, first judge whether the parameter is null

Then call zonedDateTime.toLocalDateTime().

We know that zonedDateTime and LocalDateTime can be directly converted

Method details - of(java.time.Instant, java.time.ZoneId)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.time.ZoneId)

Method description

{@ link Instant} to {@ link LocalDateTime}

Supported version and above

Parameter Description:

Parameter namedescribe
Instant instant
instant {@link Instant}
ZoneId zoneId
zoneId time zone

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-21T11:23:56";
		final DateTime dt = DateUtil.parse(dateStr);
		LocalDateTime of = LocalDateTimeUtil.of(dt.getTime(), ZoneId.of("UTC"));
		Assert.assertNotNull(of);
		Assert.assertEquals(dateStr, of.toString());

		of = LocalDateTimeUtil.of(dt.getTime(), ZoneId.of("Asia/Shanghai"));
		Assert.assertNotNull(of);
		Assert.assertEquals("2021-05-21T19:23:56", of.toString());

Source code analysis:

	public static LocalDateTime of(Instant instant, ZoneId zoneId) {
		if (null == instant) {
			return null;
		}

		return LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()));
	}

Here, first judge whether the parameter is null

Then, execute LocalDateTime.ofInstant(instant, ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault()))

There are two parts:

1,ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault())

2,LocalDateTime.ofInstant(instant, zoneId)

ObjectUtil.defaultIfNull(zoneId, ZoneId.systemDefault())

	public static <T> T defaultIfNull(final T object, final T defaultValue) {
		return (null != object) ? object : defaultValue;
	}

This is easy to understand. Judge whether the value is null. If it is, return the default value. If not, return the original value.

**LocalDateTime.ofInstant(instant, zoneId) * * is jdk8's own source generated method

Method details - of(java.time.Instant, java.util.TimeZone)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(java.time.Instant, java.util.TimeZone)

Method description

{@ link Instant} to {@ link LocalDateTime}

Supported version and above

Parameter Description:

Parameter namedescribe
Instant instant
instant {@link Instant}
TimeZone timeZone
timeZone time zone

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-21T11:23:56";
		// The Instant obtained through conversion is UTC time
		Instant instant1 = DateUtil.parse(dateStr).toInstant();
		LocalDateTime localDateTime = LocalDateTimeUtil.of(instant1,TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")));
		Assert.assertEquals("2021-05-21T19:23:56", localDateTime.toString());
		System.out.println(localDateTime);

Source code analysis:

	public static LocalDateTime of(Instant instant, TimeZone timeZone) {
		if (null == instant) {
			return null;
		}

		return of(instant, ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()).toZoneId());
	}

Here, first judge whether the parameter is null

Then, execute LocalDateTime.ofInstant(timeZone, zoneId)

There are two parts:

1,ObjectUtil.defaultIfNull(timeZone, ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()).toZoneId())

2,LocalDateTime.ofInstant(timeZone, zoneId)

ObjectUtil.defaultIfNull(timeZone, ObjectUtil.defaultIfNull(timeZone, TimeZone.getDefault()).toZoneId())

	public static <T> T defaultIfNull(final T object, final T defaultValue) {
		return (null != object) ? object : defaultValue;
	}

This is easy to understand. Judge whether the value is null. If it is, return the default value. If not, return the original value.

**LocalDateTime.ofInstant(instant, zoneId) * * is jdk8's own source generated method

Method details - of(long)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(long)

Method description

Milliseconds to {@ link LocalDateTime}, using the default time zone

Note: this method uses the default time zone. If it is not UTC, it will produce a time offset

Supported version and above

Parameter Description:

Parameter namedescribe
long epochMilli
epochMilli the number of milliseconds counted from 1970-01-01T00:00:00Z

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-22 10:23:56";
		Long time = DateUtil.parse(dateStr).getTime();
		// Use default time zone
		LocalDateTime localDateTime = LocalDateTimeUtil.of(time);
		Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());
		System.out.println(localDateTime);

Source code analysis:

	public static LocalDateTime of(long epochMilli) {
		return of(Instant.ofEpochMilli(epochMilli));
	}

This is to convert long into Instant

public static Instant ofEpochMilli(long epochMilli) {
        long secs = Math.floorDiv(epochMilli, 1000);
        int mos = (int)Math.floorMod(epochMilli, 1000);
        return create(secs, mos * 1000_000);
    }

Then call of(Instant)

public static LocalDateTime of(Instant instant) {
   return of(instant, ZoneId.systemDefault());
}

Method details - ofUTC(long)

Method name: cn.hutool.core.date.LocalDateTimeUtil.ofUTC(long)

Method description

MS to {@ link LocalDateTime}, using UTC time zone

Supported version and above

Parameter Description:

Parameter namedescribe
long epochMilli
epochMilli the number of milliseconds counted from 1970-01-01T00:00:00Z

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-22T10:23:56";
		Long time = DateUtil.parse(dateStr).getTime();
		// Use UTC time zone
		LocalDateTime localDateTime = LocalDateTimeUtil.ofUTC(time);
		Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());
		System.out.println(localDateTime);

Source code analysis:

public static LocalDateTime ofUTC(long epochMilli) {
		return ofUTC(Instant.ofEpochMilli(epochMilli));
	}

This is to convert long into Instant

public static Instant ofEpochMilli(long epochMilli) {
        long secs = Math.floorDiv(epochMilli, 1000);
        int mos = (int)Math.floorMod(epochMilli, 1000);
        return create(secs, mos * 1000_000);
    }

Then call ofUTC(Instant)

public static LocalDateTime ofUTC(Instant instant) {
		return of(instant, ZoneId.of("UTC"));
	}

Method details - of(long, java.time.ZoneId)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(long, java.time.ZoneId)

Method description

Milliseconds to {@ link LocalDateTime}. Depending on the time zone, the result will have a time offset

Supported version and above

Parameter Description:

Parameter namedescribe
long epochMilli
epochMilli the number of milliseconds counted from 1970-01-01T00:00:00Z
ZoneId zoneId
zoneId time zone

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-22T10:23:56";
		Long time = DateUtil.parse(dateStr).getTime();

		LocalDateTime localDateTime = LocalDateTimeUtil.of(time,ZoneId.of("Asia/Shanghai"));
		Assert.assertEquals("2021-05-22T18:23:56", localDateTime.toString());

Source code analysis:

/**
	 * Milliseconds to {@ link LocalDateTime}. Depending on the time zone, the result will have a time offset
	 *
	 * @param epochMilli Number of milliseconds counted from 1970-01-01T00:00:00Z
	 * @param zoneId     time zone
	 * @return {@link LocalDateTime}
	 */
	public static LocalDateTime of(long epochMilli, ZoneId zoneId) {
		return of(Instant.ofEpochMilli(epochMilli), zoneId);
	}

This is to convert long into Instant

public static Instant ofEpochMilli(long epochMilli) {
        long secs = Math.floorDiv(epochMilli, 1000);
        int mos = (int)Math.floorMod(epochMilli, 1000);
        return create(secs, mos * 1000_000);
    }

Then call of(Instant, zoneId)

The above method has been analyzed many times, so the number of water words will not be repeated.

Method details - of(long, java.util.TimeZone)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(long, java.util.TimeZone)

Method description

Milliseconds to {@ link LocalDateTime}, resulting in a time offset

Supported version and above

Parameter Description:

Parameter namedescribe
long epochMilli
epochMilli the number of milliseconds counted from 1970-01-01T00:00:00Z
TimeZone timeZone
timeZone time zone

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-22T10:23:56";
		Long time = DateUtil.parse(dateStr).getTime();

		LocalDateTime localDateTime = LocalDateTimeUtil.of(time, TimeZone.getTimeZone(ZoneId.of("Asia/Shanghai")));
		Assert.assertEquals("2021-05-22T18:23:56", localDateTime.toString());

Source code analysis:

public static LocalDateTime of(long epochMilli, TimeZone timeZone) {
		return of(Instant.ofEpochMilli(epochMilli), timeZone);
	}

This is to convert long into Instant

public static Instant ofEpochMilli(long epochMilli) {
        long secs = Math.floorDiv(epochMilli, 1000);
        int mos = (int)Math.floorMod(epochMilli, 1000);
        return create(secs, mos * 1000_000);
    }

Then call of(Instant, timeZone)

The above method has been analyzed many times, so the number of water words will not be repeated.

Method details -of(java.util.Date)

Method name: cn.hutool.core.date.LocalDateTimeUtil.of(java.util.Date)

Method description

{@ link Date} to {@ link LocalDateTime}, using the default time zone

Supported version and above

Parameter Description:

Parameter namedescribe
Date date
Date object

Return value:

{@link LocalDateTime}

Reference case:

	String dateStr = "2021-05-22 10:23:56";
		DateTime date = DateUtil.parse(dateStr);
		//Use default time zone
		LocalDateTime localDateTime = LocalDateTimeUtil.of(date);
		Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());

Source code analysis:

	public static LocalDateTime of(Date date) {
		if (null == date) {
			return null;
		}

		if (date instanceof DateTime) {
			return of(date.toInstant(), ((DateTime) date).getZoneId());
		}
		return of(date.toInstant());
	}

This method is to strongly convert Date to LocalDateTime

Good habit. First judge whether the parameter date is empty

if (date instanceof DateTime) {
			return of(date.toInstant(), ((DateTime) date).getZoneId());
		}

This DateTime is an object encapsulated by hutool. It inherits from Date and encapsulates some common methods

If it is not the first two, of(date.Instant) is called

Method details - of (Java. Time. Temporary. Temporalaccessor)

Method name: cn.hutool.core.date.localdatetimeutil.of (Java. Time. Temporary. Temporalaccessor)

Method description

{@ link TemporalAccessor} go to {@ link LocalDateTime} and use the default time zone

Supported version and above

Parameter Description:

Parameter namedescribe
TemporalAccessor temporalAccessor
temporalAccessor {@link TemporalAccessor}

Return value:

{@link LocalDateTime}

Reference case:

		String dateStr = "2021-05-22T10:23:56";
		//Use default time zone
		TemporalAccessor temporalAccessor = DateTimeFormatter.ISO_DATE_TIME.parse(dateStr);
		LocalDateTime localDateTime = LocalDateTimeUtil.of(temporalAccessor);
		Assert.assertEquals("2021-05-22T10:23:56", localDateTime.toString());

Source code analysis:

	public static LocalDateTime of(TemporalAccessor temporalAccessor) {
		if (null == temporalAccessor) {
			return null;
		}

		if(temporalAccessor instanceof LocalDate){
			return ((LocalDate)temporalAccessor).atStartOfDay();
		}

		return LocalDateTime.of(
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.HOUR_OF_DAY),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.MINUTE_OF_HOUR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.SECOND_OF_MINUTE),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.NANO_OF_SECOND)
		);
	}

Because the implementation classes of TemporalAccessor time are commonly used as follows (provided by java8):

  • LocalDateTime
  • LocalDate
  • LocalTime

Good habit. First judge whether the parameter temporalAccessor is empty

Then judge whether the temporalAccessor is a localDate object. If so, call LocalDate.atStartOfDay(), and the return value is localDate + '00:00'

//LocalDate
public LocalDateTime atStartOfDay() {
        return LocalDateTime.of(this, LocalTime.MIDNIGHT);
    }
/**
 * The time of midnight at the start of the day, '00:00'.
 */
public static final LocalTime MIDNIGHT;
public static LocalDateTime of(LocalDate date, LocalTime time) {
    Objects.requireNonNull(date, "date");
    Objects.requireNonNull(time, "time");
    return new LocalDateTime(date, time);
}

Finally, get the value of the LocalDateTime object through the LocalDateTime.of method.

However, the blogger found a problem. There is no month, year and day in LocalTime. How to convert it into LocalDateTime? Let's write a demo to see the effect

LocalTime localTime = LocalTime.now();
LocalDateTime localDateTime = LocalDateTimeUtil.of(localTime);
System.out.println(localDateTime);

Why didn't you report an error

return LocalDateTime.of(
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.HOUR_OF_DAY),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.MINUTE_OF_HOUR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.SECOND_OF_MINUTE),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.NANO_OF_SECOND)
		);

Here are also the methods encapsulated by hutool. They all call * * public static int get (temporalaccessor, temporalaccessor, temporalfield) * * the source code is as follows

public static int get(TemporalAccessor temporalAccessor, TemporalField field) {
   if (temporalAccessor.isSupported(field)) {
      return temporalAccessor.get(field);
   }

   return (int)field.range().getMinimum();
}

This code is easy to understand. It is to take the property value corresponding to the temporalAccessor object. If it does not exist, take the minimum value of this property value.

To see the effect:

1. localtime does not have the year attribute

2. Take the minimum value of this field.

Other fields are obtained in the same way.

Method details - ofdate (Java. Time. Temporary. Temporalaccessor)

Method name: cn.hutool.core.date.localdatetimeutil.ofdate (Java. Time. Temporary. Temporalaccessor)

Method description

{@ link TemporalAccessor} to {@ link LocalDate}, using the default time zone

Supported version and above

5.3.10

Parameter Description:

Parameter namedescribe
TemporalAccessor temporalAccessor
temporalAccessor {@link TemporalAccessor}

Return value:

{@link LocalDate}

Reference case:

		String dateStr = "2021-05-22T10:23:56";
		//Use default time zone
		TemporalAccessor temporalAccessor = DateTimeFormatter.ISO_DATE_TIME.parse(dateStr);
		LocalDate localDate = LocalDateTimeUtil.ofDate(temporalAccessor);
		Assert.assertEquals("2021-05-22", localDate.toString());

Source code analysis:

	public static LocalDate ofDate(TemporalAccessor temporalAccessor) {
		if (null == temporalAccessor) {
			return null;
		}

		if(temporalAccessor instanceof LocalDateTime){
			return ((LocalDateTime)temporalAccessor).toLocalDate();
		}

		return LocalDate.of(
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.YEAR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.MONTH_OF_YEAR),
				TemporalAccessorUtil.get(temporalAccessor, ChronoField.DAY_OF_MONTH)
		);
	}

Because the implementation classes of TemporalAccessor time are commonly used as follows (provided by java8):

  • LocalDateTime
  • LocalDate
  • LocalTime

Good habit. First judge whether the parameter temporalAccessor is empty

Then judge whether the temporalAccessor is a LocalDateTime object. If so, call LocalDateTime.toLocalDate(), and the return value is localDate, because LocalDateTime=localDate+LocalTime

Finally, get the value of the LocalDate object through the LocalDate.of method.

Method details - parse(java.lang.CharSequence)

Method name: cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence)

Method description

The parsed date time string is {@ link LocalDateTime}. Only yyyy MM DD'T 'HH:mm:ss format is supported, for example: 2007-12-03T10:15:30

Supported version and above

Parameter Description:

Parameter namedescribe
CharSequence text
Textdate time string

Return value:

{@link LocalDateTime}

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
		Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());

Source code analysis:

	/**
	 * The parsed date time string is {@ link LocalDateTime}. Only yyyy MM DD't'hh: mm: SS format is supported, for example: 2007-12-03T10:15:30
	 *
	 * @param text      Date time string
	 * @return {@link LocalDateTime}
	 */
	public static LocalDateTime parse(CharSequence text) {
		return parse(text, (DateTimeFormatter)null);
	}

Please see the source code analysis below.

Method details - parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)

Method name: cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.time.format.DateTimeFormatter)

Method description

The parsed date time string is {@ link LocalDateTime}. The format supports date time, date and time

Supported version and above

Parameter Description:

Parameter namedescribe
CharSequence text
Textdate time string when the formatter is null, the string should conform to the format 2020-01-23T12:23:56
DateTimeFormatter formatter
Formatter date formatter. See {@ link DateTimeFormatter} for the predefined format

Return value:

{@link LocalDateTime}

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56", DateTimeFormatter.ISO_DATE_TIME);
		Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());
		System.out.println(localDateTime);

Source code analysis:

	public static LocalDateTime parse(CharSequence text, DateTimeFormatter formatter) {
		if (null == text) {
			return null;
		}
		if (null == formatter) {
			return LocalDateTime.parse(text);
		}

		return of(formatter.parse(text));
	}

If some students are unfamiliar with CharSequence object, they should not be unfamiliar with String, which is the implementation interface of CharSequence

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    ...
    }

DateTimeFormatter is a date and time formatter provided by jdk8 to replace our old friend simpledateformat.

Good habit. First judge whether the parameter CharSequence is empty

Then judge whether the parameter DateTimeFormatter is empty. If it is empty, call LocalDateTime.parse(text) directly

Let's look at the source code

public static LocalDateTime parse(CharSequence text) {
    return parse(text, DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}

The date format string used here should be in this format:

such as '2011-12-03T10:15:30'

What happens if the passed CharSequence parameter is not a string in this format

//According to format 2020-01-23T12:23:56
LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56", DateTimeFormatter.ISO_DATE_TIME);
Assert.assertEquals("2020-01-23T12:23:56", localDateTime.toString());
System.out.println(localDateTime);

//Unformatted
DateTimeFormatter dateTimeFormatter = null;
localDateTime = LocalDateTimeUtil.parse("2020-01-23", dateTimeFormatter);
System.out.println(localDateTime);

The result of the implementation is expected, and the error is reported directly. This is a pit. Everyone should pay attention to it

java.time.format.DateTimeParseException: Text '2020-01-23' could not be parsed at index 10

Finally, call of(formatter.parse(text)).

formatter.parse(text) returns TemporalAccessor, not necessarily the LocalDateTime we want, so we need to turn it through of again

formatter.parse(text) is a native JDK8 method.

Method details - parse(java.lang.CharSequence, java.lang.String)

Method name: cn.hutool.core.date.LocalDateTimeUtil.parse(java.lang.CharSequence, java.lang.String)

Method description

Resolve the date time string to {@ link LocalDateTime}

Supported version and above

Parameter Description:

Parameter namedescribe
CharSequence text
Textdate time string
String format
Format date format, similar to yyyy MM DD HH: mm: SS, SSS

Return value:

{@link LocalDateTime}

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23", DatePattern.NORM_DATE_PATTERN);
		Assert.assertEquals("2020-01-23T00:00", localDateTime.toString());

Source code analysis:

	public static LocalDateTime parse(CharSequence text, String format) {
		if (null == text) {
			return null;
		}

		DateTimeFormatter formatter = null;
		if(StrUtil.isNotBlank(format)){
			// Fix the problem that yyyyMMddHHmmssSSS format cannot be resolved
			// fix issue#1082
			//see https://stackoverflow.com/questions/22588051/is-java-time-failing-to-parse-fraction-of-second
			// jdk8 bug at: https://bugs.openjdk.java.net/browse/JDK-8031085
			if(StrUtil.startWithIgnoreEquals(format, DatePattern.PURE_DATETIME_PATTERN)){
				final String fraction = StrUtil.removePrefix(format, DatePattern.PURE_DATETIME_PATTERN);
				if(ReUtil.isMatch("[S]{1,2}", fraction)){
					//Replace the dates of yyyyMMddHHmmssS and yyyyMMddHHmmssS with yyyyMMddHHmmssS format, and supplement with 0
					text += StrUtil.repeat('0', 3-fraction.length());
				}
				formatter = new DateTimeFormatterBuilder()
						.appendPattern(DatePattern.PURE_DATETIME_PATTERN)
						.appendValue(ChronoField.MILLI_OF_SECOND, 3)
						.toFormatter();
			} else{
				formatter = DateTimeFormatter.ofPattern(format);
			}
		}

		return parse(text, formatter);
	}

Form a good habit. First judge whether the parameters CharSequence and format are empty

Here, a bug in jdk8 is handled compatibly

1. In normal configuration, string dates in standard format can be converted normally. If the month, day, hour, minute and second are less than two digits, you need to fill in 0. Otherwise, the conversion will fail and an exception will be thrown.

		DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
		LocalDateTime dt1 = LocalDateTime.parse("2021-7-20 23:46:43.946", DATE_TIME_FORMATTER);
		System.out.println(dt1);

Error will be reported:

java.time.format.DateTimeParseException: Text '2021-7-20 23:46:43.946' could not be parsed at index 5

Analysis reason: the format string does not match the actual time

"yyyy-MM-dd HH:mm:ss.SSS"

"2021-7-20 23:46:43.946"

The middle month format is MM, and the actual time is 7

Solution: keep the format string matching the actual time

	DateTimeFormatter DATE_TIME_FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
		LocalDateTime dt1 = LocalDateTime.parse("2021-07-20 23:46:43.946", DATE_TIME_FORMATTER);
		System.out.println(dt1);

Method details - parseDate(java.lang.CharSequence)

Method name: cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence)

Method description

The parsed date and time string is {@ link LocalDate}. Only yyyy MM DD'T 'HH:mm:ss format is supported, for example: 2007-12-03T10:15:30

Supported version and above

5.3.10

Parameter Description:

Parameter namedescribe
CharSequence text
Textdate time string

Return value:

{@link LocalDate}

Reference case:

		LocalDate localDate = LocalDateTimeUtil.parseDate("2020-01-23");		Assert.assertEquals("2020-01-23", localDate.toString());

Source code analysis:

	/**
	 * The parsed date and time string is {@ link LocalDate}. Only yyyy mm dd't'hh: mm: SS format is supported, for example: 2007-12-03T10:15:30
	 *
	 * @param text      Date time string
	 * @return {@link LocalDate}
	 * @since 5.3.10
	 */
	public static LocalDate parseDate(CharSequence text) {
		return parseDate(text, (DateTimeFormatter)null);
	}

Please see the source code analysis below.

Method details - parseDate(java.lang.CharSequence, java.time.format.DateTimeFormatter)

Method name: cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.time.format.DateTimeFormatter)

Method description

The parsed date time string is {@ link LocalDate}, and the format supports date

Supported version and above

5.3.10

Parameter Description:

Parameter namedescribe
CharSequence text
Textdate time string
DateTimeFormatter formatter
Formatter date formatter. See {@ link DateTimeFormatter} for the predefined format

Return value:

{@link LocalDate}

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("12:23:56", DatePattern.NORM_TIME_PATTERN);
		Assert.assertEquals("12:23:56", localDateTime.toLocalTime().toString());

Source code analysis:

	public static LocalDate parseDate(CharSequence text, DateTimeFormatter formatter) {
		if (null == text) {
			return null;
		}
		if (null == formatter) {
			return LocalDate.parse(text);
		}

		return ofDate(formatter.parse(text));
	}

If some students are unfamiliar with CharSequence object, they should not be unfamiliar with String, which is the implementation interface of CharSequence

public final class String
    implements java.io.Serializable, Comparable<String>, CharSequence {
    ...
    }

DateTimeFormatter is a date and time formatter provided by jdk8 to replace our old friend simpledateformat.

Good habit. First judge whether the parameter CharSequence is empty

Then judge whether the parameter DateTimeFormatter is empty. If it is empty, call LocalDate.parse(text) directly

Let's look at the source code

 public static LocalDate parse(CharSequence text) {
        return parse(text, DateTimeFormatter.ISO_LOCAL_DATE);
    }

The date format string used here should be in this format:

such as '2011-12-03'

Finally, call of(formatter.parse(text)).

formatter.parse(text) returns TemporalAccessor, not necessarily the LocalDate we want, so we need to turn it through of again

formatter.parse(text) is a native JDK8 method.

Method details - parseDate(java.lang.CharSequence, java.lang.String)

Method name: cn.hutool.core.date.LocalDateTimeUtil.parseDate(java.lang.CharSequence, java.lang.String)

Method description

Parse date string as {@ link LocalDate}

Supported version and above

Parameter Description:

Parameter namedescribe
CharSequence text
Textdate string
String format
Format date format, similar to yyyy MM DD

Return value:

{@link LocalDateTime}

Reference case:

		//The format of the first parameter is consistent with that of the second parameter
		LocalDate localDate = LocalDateTimeUtil.parseDate("2020-01-23 12:23:56","yyyy-MM-dd hh:mm:ss");
		Assert.assertEquals("2020-01-23", localDate.toString());
		 localDate = LocalDateTimeUtil.parseDate("2020/01/23 12:23:56","yyyy/MM/dd hh:mm:ss");
		Assert.assertEquals("2020-01-23", localDate.toString());

Source code analysis:

	public static LocalDate parseDate(CharSequence text, String format) {
		if (null == text) {
			return null;
		}
		return parseDate(text, DateTimeFormatter.ofPattern(format));
	}

Please see the source code analysis above.

Method details - formatNormal(java.time.LocalDateTime)

Method name: cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDateTime)

Method description

Format the date and time in yyyy MM DD HH: mm: SS format

Supported version and above

5.3.11

Parameter Description:

Parameter namedescribe
LocalDateTime time
time {@link LocalDateTime}

Return value:

Formatted string

Reference case:

        final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
	    String	format = LocalDateTimeUtil.formatNormal(localDateTime);
		Assert.assertEquals("2020-01-23 12:23:56", format);

Source code analysis:

	/**
	 * Format the date and time in yyyy MM DD HH: mm: SS format
	 *
	 * @param time      {@link LocalDateTime}
	 * @return Formatted string
	 * @since 5.3.11
	 */
	public static String formatNormal(LocalDateTime time) {
		return format(time, DatePattern.NORM_DATETIME_FORMATTER);
	}

//------------------------------
public static String format(LocalDateTime time, DateTimeFormatter formatter) {
		return TemporalAccessorUtil.format(time, formatter);
	}

TemporalAccessorUtil class is a tool class encapsulated by hutool. It is easy to understand from the following source code.

//TemporalAccessorUtil
/**
 * Format the date and time in the specified format
 *
 * @param time      {@link TemporalAccessor}
 * @param formatter Date formatter. For the predefined format, see: {@ link DateTimeFormatter}
 * @return Formatted string
 * @since 5.3.10
 */
public static String format(TemporalAccessor time, DateTimeFormatter formatter) {
   if (null == time) {
      return null;
   }

   if(null == formatter){
      formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
   }


   try {
      return formatter.format(time);
   } catch (UnsupportedTemporalTypeException e){
      if(time instanceof LocalDate && e.getMessage().contains("HourOfDay")){
         // The user passed in LocalDate, but it is required to format the part with time. Convert it to LocalDateTime and try again
         return formatter.format(((LocalDate) time).atStartOfDay());
      }else if(time instanceof LocalTime && e.getMessage().contains("YearOfEra")){
         // The user passed in LocalTime, but it is required to format the part with date. Convert it to LocalDateTime and try again
         return formatter.format(((LocalTime) time).atDate(LocalDate.now()));
      }
      throw e;
   }
}

Form a good habit. First judge whether the parameters TemporalAccessor and DateTimeFormatter are empty

If DateTimeFormatter is empty, the default value is DateTimeFormatter.ISO_LOCAL_DATE_TIME

such as '2011-12-03T10:15:30'

Then call the formatting method formatter.format(time). If time is not a LocalDateTime object, it will report errors, then do compatibility processing in catch, LocalDate and LocalTime objects can be formatted, and others will return to the exception directly.

Method details - format(java.time.LocalDateTime, java.time.format.DateTimeFormatter)

Method name: cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.time.format.DateTimeFormatter)

Method description

Format the date and time in the specified format

Supported version and above

Parameter Description:

Parameter namedescribe
LocalDateTime time
time {@link LocalDateTime}
DateTimeFormatter formatter
Formatter date formatter. See {@ link DateTimeFormatter} for the predefined format

Return value:

Formatted string

Reference case:

		LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
		String format = LocalDateTimeUtil.format(localDateTime, DateTimeFormatter.ISO_DATE_TIME);
		Assert.assertEquals("2020-01-23T12:23:56", format);

Source code analysis:

	/**
	 * Format the date and time in the specified format
	 *
	 * @param time      {@link LocalDateTime}
	 * @param formatter Date formatter. For the predefined format, see: {@ link DateTimeFormatter}
	 * @return Formatted string
	 */
	public static String format(LocalDateTime time, DateTimeFormatter formatter) {
		return TemporalAccessorUtil.format(time, formatter);
	}

Please see the source code analysis above.

Method details - format(java.time.LocalDateTime, java.lang.String)

Method name: cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDateTime, java.lang.String)

Method description

Format the date and time in the specified format

Supported version and above

Parameter Description:

Parameter namedescribe
LocalDateTime time
time {@link LocalDateTime}
String format
Format date format, similar to yyyy MM DD HH: mm: SS, SSS

Return value:

Formatted string

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
		String format = LocalDateTimeUtil.format(localDateTime, DatePattern.NORM_DATETIME_PATTERN);
		Assert.assertEquals("2020-01-23 12:23:56", format);

Source code analysis:

	public static String format(LocalDateTime time, String format) {
		if (null == time) {
			return null;
		}
		return format(time, DateTimeFormatter.ofPattern(format));
	}

DateTimeFormatter.ofPattern(format) will return DateTimeFormatter after execution

The format(time, DateTimeFormatter method is then called

Please see the source code analysis above.

Method details - formatNormal(java.time.LocalDate)

Method name: cn.hutool.core.date.LocalDateTimeUtil.formatNormal(java.time.LocalDate)

Method description

Format the date and time in yyyy MM DD format

Supported version and above

5.3.11

Parameter Description:

Parameter namedescribe
LocalDate date
date {@link LocalDate}

Return value:

Formatted string

Reference case:

		final LocalDate date = LocalDate.parse("2020-01-23");
		String format = LocalDateTimeUtil.format(date, DatePattern.NORM_DATE_PATTERN);
		Assert.assertEquals("2020-01-23", format);

		format = LocalDateTimeUtil.formatNormal(date);
		Assert.assertEquals("2020-01-23", format);

Source code analysis:

public static String formatNormal(LocalDate date) {
		return format(date, DatePattern.NORM_DATE_FORMATTER);
	}

Please see the source code analysis above.

Method details - format(java.time.LocalDate, java.time.format.DateTimeFormatter)

Method name: cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.time.format.DateTimeFormatter)

Method description

Format the date and time in the specified format

Supported version and above

5.3.10

Parameter Description:

Parameter namedescribe
LocalDate date
date {@link LocalDate}
DateTimeFormatter formatter
Formatter date formatter. See {@ link DateTimeFormatter} for the predefined format

Return value:

Formatted string

Reference case:

		final LocalDate date = LocalDate.parse("2021-05-22");
		String format = LocalDateTimeUtil.format(date, DateTimeFormatter.ISO_DATE);
		Assert.assertEquals("2021-05-22", format);

Source code analysis:

	public static String format(LocalDate date, DateTimeFormatter formatter) {
		return TemporalAccessorUtil.format(date, formatter);
	}

Please see the source code analysis above.

Method details - format(java.time.LocalDate, java.lang.String)

Method name: cn.hutool.core.date.LocalDateTimeUtil.format(java.time.LocalDate, java.lang.String)

Method description

Format the date and time in the specified format

Supported version and above

5.3.10

Parameter Description:

Parameter namedescribe
LocalDate date
date {@link LocalDate}
String format
Format date format, similar to yyyy MM DD

Return value:

Formatted string

Reference case:

		final LocalDate date = LocalDate.parse("2020-01-23");
		String format = LocalDateTimeUtil.format(date, DatePattern.NORM_DATE_PATTERN);
		Assert.assertEquals("2020-01-23", format);

Source code analysis:

	public static String format(LocalDate date, String format) {
		if (null == date) {
			return null;
		}
		return format(date, DateTimeFormatter.ofPattern(format));
	}

Please see the source code analysis above.

Method details - offset (Java. Time. Localdatetime, long, Java. Time. Temporary. Temporalunit)

Method name: cn.hutool.core.date.localdatetimeutil.offset (java.time.localdatetime, long, java.time.temporary.temporalunit)

Method description

Date offset: add different values according to different field s (offset will modify the incoming objects)

Supported version and above

Parameter Description:

Parameter namedescribe
LocalDateTime time
time {@link LocalDateTime}
long number
Number offset, a positive number is a backward offset, and a negative number is a forward offset
TemporalUnit field
field offset unit, see {@ link chrononunit}, cannot be null

Return value:

Date and time after offset

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
		LocalDateTime offset = LocalDateTimeUtil.offset(localDateTime, 1, ChronoUnit.DAYS);
		// Not the same object
		Assert.assertNotSame(localDateTime, offset);

		Assert.assertEquals("2020-01-24T12:23:56", offset.toString());

Source code analysis:

	/**
	 * Date offset: add different values according to different field s (offset will modify the incoming objects)
	 *
	 * @param time   {@link LocalDateTime}
	 * @param number Offset. Positive numbers are backward offsets and negative numbers are forward offsets
	 * @param field  Offset unit, see {@ link chrononunit}, cannot be null
	 * @return Date and time after offset
	 */
	public static LocalDateTime offset(LocalDateTime time, long number, TemporalUnit field) {
		if (null == time) {
			return null;
		}

		return time.plus(number, field);
	}

time.plus(number, field) is the method provided by jdk8

	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);

Method details - between(java.time.LocalDateTime, java.time.LocalDateTime)

Method name: cn.hutool.core.date.LocalDateTimeUtil.between(java.time.LocalDateTime, java.time.LocalDateTime)

Method description

Gets the difference between two dates. If the end time is earlier than the start time, the result is negative.

The returned result is the {@ link Duration} object. The phase difference unit ### supported version and above is returned by calling the toXXX method

Parameter Description:

Parameter namedescribe
LocalDateTime startTimeInclude
startTimeInclude start time (inclusive)
LocalDateTime endTimeExclude
endTimeExclude end time (not included)

Return value:

Time difference {@ link Duration} object

Reference case:

		final Duration between = LocalDateTimeUtil.between(
				LocalDateTimeUtil.parse("2019-02-02T00:00:00"),
				LocalDateTimeUtil.parse("2020-02-02T00:00:00"));
		Assert.assertEquals(365, between.toDays());

Source code analysis:

	public static Duration between(LocalDateTime startTimeInclude, LocalDateTime endTimeExclude) {
		return TemporalUtil.between(startTimeInclude, endTimeExclude);
	}

TemporalUtil is a tool class encapsulated by hutool. The source code is as follows:

/**
 * Gets the difference between two dates. If the end time is earlier than the start time, the result is negative.
 * <p>
 * The returned result is the {@ link Duration} object, and the phase difference unit is returned by calling the toXXX method
 *
 * @param startTimeInclude Start time (inclusive)
 * @param endTimeExclude   End time (not included)
 * @return Time difference {@ link Duration} object
 */
public static Duration between(Temporal startTimeInclude, Temporal endTimeExclude) {
   return Duration.between(startTimeInclude, endTimeExclude);
}

Duration is suitable for shorter processing time and requires higher accuracy. We can use the between() method to compare the difference between two moments.

Duration.between is a method provided by JDK8.

Method details - between (Java. Time. Localdatetime, Java. Time. Localdatetime, Java. Time. Temporary. Chrononunit)

Method name: cn.hutool.core.date.localdatetimeutil.between (java.time.localdatetime, java.time.localdatetime, Java. Time. Temporary. Chrononunit)

Method description

Gets the difference between two dates. If the end time is earlier than the start time, the result is negative.

The return result is a long value of time difference

Supported version and above

5.4.5

Parameter Description:

Parameter namedescribe
LocalDateTime startTimeInclude
startTimeInclude start time (inclusive)
LocalDateTime endTimeExclude
endTimeExclude end time (excluding)
ChronoUnit unit
Unit time difference unit

Return value:

time difference

Reference case:

		final long betweenWeek = DateUtil.betweenWeek(
				DateUtil.parse("2020-11-21"),
				DateUtil.parse("2020-11-23"), false);

		final long betweenWeek2 = LocalDateTimeUtil.between(
				LocalDateTimeUtil.parse("2020-11-21", "yyy-MM-dd"),
				LocalDateTimeUtil.parse("2020-11-23", "yyy-MM-dd"),
				ChronoUnit.WEEKS);
		Assert.assertEquals(betweenWeek, betweenWeek2);

Source code analysis:

public static long between(LocalDateTime startTimeInclude, LocalDateTime endTimeExclude, ChronoUnit unit) {
		return TemporalUtil.between(startTimeInclude, endTimeExclude, unit);
	}

One more time unit option

public static long between(Temporal startTimeInclude, Temporal endTimeExclude, ChronoUnit unit) {
   return unit.between(startTimeInclude, endTimeExclude);
}

The returned data is 0

The returned data is 1

The data of these two demo s reflect that the results are generated in units of time difference.

Method details - betweenPeriod(java.time.LocalDate, java.time.LocalDate)

Method name: cn.hutool.core.date.LocalDateTimeUtil.betweenPeriod(java.time.LocalDate, java.time.LocalDate)

Method description

Get the apparent time difference between two dates. If the end time is earlier than the start time, the result is negative.

For example, February 1, 2011 and August 11, 2021 differ by 10 days and 6 months respectively

Supported version and above

5.4.5

Parameter Description:

Parameter namedescribe
LocalDate startTimeInclude
startTimeInclude start time (inclusive)
LocalDate endTimeExclude
endTimeExclude end time (excluding)

Return value:

time difference

Reference case:

		final LocalDate localDate1= LocalDate.parse("2021-05-22");
		final LocalDate localDate2= LocalDate.parse("2021-06-23");

		Period period = LocalDateTimeUtil.betweenPeriod(localDate1,localDate2);
		Assert.assertEquals(1, period.getMonths());
		Assert.assertEquals(1, period.getDays());

		period = LocalDateTimeUtil.betweenPeriod(localDate2,localDate1);
		Assert.assertEquals(-1, period.getMonths());
		Assert.assertEquals(-1, period.getDays());
		final LocalDate localDate3= LocalDate.parse("2021-06-22");
		period = LocalDateTimeUtil.betweenPeriod(localDate1,localDate3);
		Assert.assertEquals(1, period.getMonths());
		Assert.assertEquals(0, period.getDays());

Source code analysis:

public static Period betweenPeriod(LocalDate startTimeInclude, LocalDate endTimeExclude) {
		return Period.between(startTimeInclude, endTimeExclude);
	}

Period.between is the method provided by JDK8

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.

	LocalDate first = LocalDate.of(2021, 8, 29);
	LocalDate second = LocalDate.of(2022, 9, 30);
	Period period = Period.between(first, second);
	System.out.println(period);

Method details - beginOfDay(java.time.LocalDateTime)

Method name: cn.hutool.core.date.LocalDateTimeUtil.beginOfDay(java.time.LocalDateTime)

Method description

Modify to the start time of the day, for example: 2020-02-02 00:00:00000

Supported version and above

Parameter Description:

Parameter namedescribe
LocalDateTime time
Time date time

Return value:

Start time of the day

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
		final LocalDateTime beginOfDay = LocalDateTimeUtil.beginOfDay(localDateTime);
		Assert.assertEquals("2020-01-23T00:00", beginOfDay.toString());

Source code analysis:

/**
	 * Modify to the start time of the day, for example: 2020-02-02 00:00:00000
	 *
	 * @param time Date time
	 * @return Start time of the day
	 */
	public static LocalDateTime beginOfDay(LocalDateTime time) {
		return time.with(LocalTime.MIN);
	}

LocalDateTime.with is the method provided by jdk8.

Addition, subtraction and modification of date and time

	LocalDateTime currentTime = LocalDateTime.now(); // Current date and time
	System.out.println("------------------Addition and subtraction of time and its modification-----------------------");
	//3. The addition and subtraction method of localdatetime includes all additions and subtractions of LocalDate and LocalTime. As mentioned above, only a brief introduction is given here
	System.out.println("3.Current time:" + currentTime);
	System.out.println("3.Current time plus 5 years:" + currentTime.plusYears(5));
	System.out.println("3.Current time plus 2 months:" + currentTime.plusMonths(2));
	System.out.println("3.Current time minus 2 days:" + currentTime.minusDays(2));
	System.out.println("3.Current time minus 5 hours:" + currentTime.minusHours(5));
	System.out.println("3.Current time plus 5 minutes:" + currentTime.plusMinutes(5));
	System.out.println("3.Current time plus 20 seconds:" + currentTime.plusSeconds(20));
	//It can also be used flexibly, such as adding one year back, subtracting one day forward, adding two hours back and subtracting five minutes forward
	System.out.println("3.Simultaneous modification(Add one year backward, one day forward, two hours backward and five minutes forward): " + currentTime.plusYears(1).minusDays(1).plusHours(2).minusMinutes(5));
	System.out.println("3.The revised year is 2025:" + currentTime.withYear(2025));
	System.out.println("3.Revised to December:" + currentTime.withMonth(12));
	System.out.println("3.The revision date is 27th:" + currentTime.withDayOfMonth(27));
	System.out.println("3.Modify the hour to 12:" + currentTime.withHour(12));
	System.out.println("3.Modify the minutes to 12:" + currentTime.withMinute(12));
	System.out.println("3.Modify the second to 12:" + currentTime.withSecond(12));

Method details - endOfDay(java.time.LocalDateTime)

Method name: cn.hutool.core.date.LocalDateTimeUtil.endOfDay(java.time.LocalDateTime)

Method description

Modify to the end time of the day, for example: 2020-02-02 23:59:59999

Supported version and above

Parameter Description:

Parameter namedescribe
LocalDateTime time
Time date time

Return value:

End of day

Reference case:

		final LocalDateTime localDateTime = LocalDateTimeUtil.parse("2020-01-23T12:23:56");
		final LocalDateTime endOfDay = LocalDateTimeUtil.endOfDay(localDateTime);
		Assert.assertEquals("2020-01-23T23:59:59.999999999", endOfDay.toString());

Source code analysis:

	/**
	 * Modify to the end time of the day, for example: 2020-02-02 23:59:59999
	 *
	 * @param time Date time
	 * @return End of day
	 */
	public static LocalDateTime endOfDay(LocalDateTime time) {
		return time.with(LocalTime.MAX);
	}

Please see the source code analysis above.

Method details - toepochmili (Java. Time. Temporary. Temporalaccessor)

Method name: cn.hutool.core.date.localdatetimeutil.toepochmili (Java. Time. Temporary. Temporalaccessor)

Method description

{@ link TemporalAccessor} converted to timestamp (number of milliseconds from 1970-01-01T00:00:00Z)

Supported version and above

5.4.1

Parameter Description:

Parameter namedescribe
TemporalAccessor temporalAccessor
temporalAccessor Date object

Return value:

{@ link Instant} object

Reference case:

		String dateStr = "2021-05-22";
		//The implementation class of TemporalAccessor contains Instant LocalDateTime ZonedDateTime OffsetDateTime LocalDate LocalTime OffsetTime
		LocalDate localDate = LocalDate.parse(dateStr);
		//Date object
		long time = LocalDateTimeUtil.toEpochMilli(localDate);
		Assert.assertEquals(DateUtil.parse(dateStr).getTime(), time);

Source code analysis:

public static long toEpochMilli(TemporalAccessor temporalAccessor) {
		return TemporalAccessorUtil.toEpochMilli(temporalAccessor);
	}

Temporalaccessorutil. Toepochmili (temporary accessor) is a method encapsulated by hutool.

public static long toEpochMilli(TemporalAccessor temporalAccessor) {
   return toInstant(temporalAccessor).toEpochMilli();
}

Convert the temporalAccessor object into an Instant object. Let's see how it is converted

public static Instant toInstant(TemporalAccessor temporalAccessor) {
   if (null == temporalAccessor) {
      return null;
   }

   Instant result;
   if (temporalAccessor instanceof Instant) {
      result = (Instant) temporalAccessor;
   } else if (temporalAccessor instanceof LocalDateTime) {
      result = ((LocalDateTime) temporalAccessor).atZone(ZoneId.systemDefault()).toInstant();
   } else if (temporalAccessor instanceof ZonedDateTime) {
      result = ((ZonedDateTime) temporalAccessor).toInstant();
   } else if (temporalAccessor instanceof OffsetDateTime) {
      result = ((OffsetDateTime) temporalAccessor).toInstant();
   } else if (temporalAccessor instanceof LocalDate) {
      result = ((LocalDate) temporalAccessor).atStartOfDay(ZoneId.systemDefault()).toInstant();
   } else if (temporalAccessor instanceof LocalTime) {
      // The specified local time is converted to Instant, and the date of the current day is taken
      result = ((LocalTime) temporalAccessor).atDate(LocalDate.now()).atZone(ZoneId.systemDefault()).toInstant();
   } else if (temporalAccessor instanceof OffsetTime) {
      // The specified local time is converted to Instant, and the date of the current day is taken
      result = ((OffsetTime) temporalAccessor).atDate(LocalDate.now()).toInstant();
   } else {
      result = Instant.from(temporalAccessor);
   }

   return result;
}

It is the corresponding temporalAccessor implementation class. From this source code, we can learn how to convert different time types into Instant objects.

Then convert the Instant object into millisecond long data

	Instant now = Instant.now();
	System.out.println("now:"+now);
	System.out.println(now.getEpochSecond()); // second
	System.out.println(now.toEpochMilli()); // millisecond

reference resources:

JSR

JCP official website: https://www.jcp.org/en/home/index

2020 Executive Committee (EC) elections: https://www.jcp.org/aboutJava/communityprocess/elections/2020.html

Nominees for 2020 Executive Committee Election: https://www.jcp.org/aboutJava/communityprocess/elections/2020-nominees.html

JSR-310: new date time API (I)

Time zone: https://baike.baidu.com/item/%E6%97%B6%E5%8C%BA/491122?fr=aladdin

UTC:https://baike.baidu.com/item/%E5%8D%8F%E8%B0%83%E4%B8%96%E7%95%8C%E6%97%B6/787659?fromtitle=UTC&fromid=5899996&fr=aladdin

GMT:https://baike.baidu.com/item/%E4%B8%96%E7%95%8C%E6%97%B6/692237?fromtitle=GMT&fromid=6026868&fr=aladdin

CST:https://baike.baidu.com/item/CST/14822063?fr=aladdin

DST:https://baike.baidu.com/item/%E5%A4%8F%E4%BB%A4%E6%97%B6/1809579?fromtitle=DST&fromid=1203186&fr=aladdin

ISO-8601:https://baike.baidu.com/item/ISO%208601/3910715?fr=aladdin

TZUpdater :https://www.oracle.com/java/technologies/javase/tzupdater-readme.html

IANA time zone data version: https://data.iana.org/time-zones/releases/

Time zone data version in JRE software: https://www.oracle.com/java/technologies/tzdata-versions.html

JSR-310: common calculation tools (IV)

duration: http://tutorials.jenkov.com/java-date-time/duration.html

ChronoUnit: https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/time/temporal/ChronoUnit.html

ValueRange:https://nowjava.com/docs/java-api-11/java.base/java/time/temporal/ValueRange.html#getMinimum()

Recommend relevant articles

JSR-310 series articles

Advanced JAVA development must master skills: java8 new date and time API (I) JSR-310: ZoneId time zone and offset)

Advanced JAVA development must master skills: java8 new date and time API (II) JSR-310: common date and time API)

Advanced JAVA development must master skills: java8 new date and time API (III) JSR-310: formatting and parsing)

Advanced JAVA development must master skills: java8 new date and time API (IV) JSR-310: common computing tools)

Advanced JAVA development must master skills: java8 new date and time API (V) JSR-310: actual combat + source code analysis)

Advanced JAVA development must master skills: java8 JSR-310 judges whether it is implemented in leap years and finds that there may be problems with the original author's code

hutool date time series

1dateutil (time tool class) - current time and current timestamp

2dateutil (time tool class) - common time types Date, DateTime, Calendar and TemporalAccessor (local DateTime) conversion

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

The SimpleDateFormat thread of java is unsafe. There is a problem. Virtual bamboo teaches you a variety of solutions

Source code analysis: risks and best practices for JDK to obtain the default time zone

Necessary skills for advanced JAVA Development: how to synchronize the JDK time zone rules when the time zone rules change

Today is the 13th / 100th day of continuous writing.
You can pay attention to me, praise me, comment on me and collect me.

Topics: Java java8 jdk8