The most complete network! Thoroughly understand java processing GMT / UTC date and time

itread01 2021-01-21 20:07:58
complete network thoroughly understand java

[TOC]![]( Foreword hello , I am a A Brother (YourBatman). The purpose of this series is to be clear 、 A complete date / Almost everything that time deals with case.[ Last article ]( Lay out all the concepts involved , for example GMT、UTC、 Daylight time 、 Time stamp and so on , If you haven't seen it yet , Not only strongly recommended, but ** Mandatory advice ** You go to use flowers 5 Take a minute to see , Because date time processing is more special , The actual combat must be based on the understanding of the concept , Otherwise, it's likely that you'll still see flowers in the fog .> Explain : date / Time management is a common problem in daily development , The reason is the concept of date and time 、 Unfamiliar with application scenarios , So don't ignore the first concept , This article is a practical operation , They complement each other , Be short of one cannot . There are many contents in this paper , The words are longer , Expected to exceed 2w word , It's designed to help you completely and completely Java Processing of date and time ,** I suggest you collect **, Keep it for reference .## The outline of this paper ![]( Version Convention - JDK:8# There are so many concepts in the text , As a Javaer Of course, they are the most concerned “ Concept ” stay Java The landing in the car . How to deal with time in daily work ? use Date Or JDK 8 The date and time after that API? How to solve the big problems such as cross time zone conversion .A I've always been in charge of production and maintenance , Kill and bury , So this article takes you to appreciate ,Java How to achieve GMT and UTC Of ? As we all know ,JDK In version 8 Bounded , There are two sets of processing dates / Of time API:![]( Although I always encourage abandonment Date Support only uses JSR 310 Date time type , But what? , Because of Date There's still a huge stock of users , So this article is not alone , The realization of both are described .## Date Type implementation java.util.Date stay JDK 1.0 existed , Used to indicate a date + The type of time , Even though it's very old , And this kind of responsibility is not single , It's very inconvenient to use , However, due to the historical reasons of more than ten or twenty years , Its vitality is still strong , There are a lot of users . Let's get to know Date, Take a look at the output of this example :```java@Testpublic void test1() { Date currDate = new Date(); System.out.println(currDate.toString()); // Already @Deprecated System.out.println(currDate.toLocaleString()); // Already @Deprecated System.out.println(currDate.toGMTString());}``` Run the program , Output :```javaFri Jan 15 10:22:34 CST 20212021-1-15 10:22:3415 Jan 2021 02:22:34 GMT```** First : Standard UTC Time (CST That's the offset +0800)** The second one : Local time , According to the time format displayed in the local time zone, the third :GTM Time , That's Greenwich time , You can see it's early in the morning 2 Point ( Beijing time is in the morning 10 A little bit ) The second one 、 The third is actually JDK 1.1 It's all marked as @Deprecated It's overdue , Basically no reuse . If you need to switch to local time or GTM Time output , Please use the formatter java.text.DateFormat To deal with .### Time zone / Offset TimeZone stay JDK8 Before ,Java For time zones and offsets, use `java.util.TimeZone` To express . In general , Using static methods `TimeZone#getDefault()` You can get the current JVM The time zone of execution , For example, you run programs in China , This method returns the Chinese time zone ( It's also called Beijing time zone 、 Beijing time ). Sometimes you need to do ** With time zone ** It's a time shift , for example : The return value of the interface should include Beijing time , Also show New York time . It's time to get the time zone of New York , Take Beijing time as the benchmark, and make a time zone conversion on it :```java@Testpublic void test2() { String patternStr = "yyyy-MM-dd HH:mm:ss"; // Beijing time (new Coming out is the preset time zone ) Date bjDate = new Date(); // Get the time zone of New York TimeZone newYorkTimeZone = TimeZone.getTimeZone("America/New_York"); // According to the time zone Convert Beijing time to New York time Date DateFormat newYorkDateFormat = new SimpleDateFormat(patternStr); newYorkDateFormat.setTimeZone(newYorkTimeZone); System.out.println(" This is Beijing time :" + new SimpleDateFormat(patternStr).format(bjDate)); System.out.println(" It's New York time :" + newYorkDateFormat.format(bjDate));}``` Run the program , Output :```java This is Beijing time :2021-01-15 11:48:16 It's New York time :2021-01-14 22:48:16```(11 + 24) - 22 = 13, Beijing is faster than New York 13 There's nothing wrong with it for an hour .> Be careful : Two times should mean the same moment , That is to say, the timestamp values are equal, then the problem comes , How do you know how to get the time zone of New York `America/New_York` This zoneId Well ? You can't just write a word ? The answer is of course not , There are rules to follow . Now I'll introduce two kinds of search zoneId The way , Whatever you choose :** Mode one **: use Java The program takes all available zoneId Print it out , And then look up ```java@Testpublic void test3() { String[] availableIDs = TimeZone.getAvailableIDs(); System.out.println(" You can use zoneId Total :" + availableIDs.length); for (String zoneId : availableIDs) { System.out.println(zoneId); }}``` Run the program , Output ( Most of them conform to the law :/ The former means the state ,/ The name of a city ):```java You can use zoneId Total :628Africa/AbidjanAfrica/Accra...Asia/Chongqing // Asia / Chongqing Asia/Shanghai // Asia / Shanghai Asia/Dubai // Asia / dubai ...America/New_York // America / New York America/Los_Angeles // America / Los Angeles ...Europe/London // Europe / London ...Etc/GMTEtc/GMT+0Etc/GMT+1...``` It's worth noting that there's no Asia/Beijing Oh .> Explain : This result is based on JDK 8 edition , There may be differences in the total number of outputs from different versions , But it's mainstream ZoneId It's not going to change ** Mode two **:zoneId The list is jre Maintain a text file , The path is you JDK/JRE Installation path of . The address in .\jre\lib The name of the directory is not `tzmappings` In the text file of . Open this file to ctrl + f Search can also achieve the purpose of query . These two kinds of houses can help you find ZoneId It's easy to look up in your dictionary , But there is another situation : The current city , stay **tzmappings** There's nothing in the file ( For example, not included ), How to get the time of this place to show how to break it ? Although the probability is very small , But not necessarily , After all, there are so many countries and cities in the world ~Java Naturally, this is also taken into account , So there are ways : Specifies the numeric representation of its time zone , It's also called offset ( Don't tell me the time zone of this place is unknown , That's hopeless ), The following example ```java@Testpublic void test4() { System.out.println(TimeZone.getTimeZone("GMT+08:00").getID()); System.out.println(TimeZone.getDefault().getID()); // New York time System.out.println(TimeZone.getTimeZone("GMT-05:00").getID()); System.out.println(TimeZone.getTimeZone("America/New_York").getID());}``` Run the program , Output :```javaGMT+08:00 // The effect is equivalent to Asia/ShanghaiAsia/ShanghaiGMT-05:00 // The effect is equivalent to America/New_YorkAmerica/New_York ``` It is worth noting that , You can only use `GMT+08:00`, But can't use `UTC+08:00`, The reason is explained below .#### Setting the default time zone generally ,JVM Where to run , That's the default time zone . For domestic programmers , Generally, they only touch the East eighth district , That's Beijing time ( Local time ). As international cooperation gets closer and closer , Most of the time, it needs date and time internationalization , Take a very practical example : The same application is deployed in alicloud 、 stay AWS( overseas ) We have also deployed one for overseas users , Now ** The same code ** Deployed in different time zones , How to break ? If the time zones are different , Then it will affect the result of the program , It's easy to make mistakes in computational logic , It's probably going to be a mess .Java Let's have a variety of ways to ** Manual ** Set / Modify the preset time zone :1. API The way : Force time zone to Beijing `TimeZone.setDefault(TimeZone.getDefault().getTimeZone("GMT+8"));`2. JVM Argument mode :`-Duser.timezone=GMT+8`3. Operation and maintenance setting mode : Set the operating system host time zone to Beijing time zone , This is the way to recommend , Can be totally insensitive to developers , It also facilitates the unified management of operation and maintenance , Many companies in alicloud 、 Tencent cloud 、 When deploying applications on cloud hosts at home and abroad , All of them adopt operation and maintenance to set a unified time zone : China time zone , It's managed in this way , In this way, the inconsistency of preset time zones is eliminated for the program , Developer friendly .### Irritating daylight saving time, you know , China used to use daylight saving time .> What is daylight saving time ?[ Poke here ]( The nearest thing to now is 1986 - 1991 I used daylight saving time in ( Every year, 4 The first Sunday in the middle of the month 2 When - 9 The first Sunday in the middle of the month 2 Time stops ):*1986 year 5 month 4 solstice 9 month 14 Japan **1987 year 4 month 12 solstice 9 month 13 Japan **1988 year 4 month 10 solstice 9 month 11 Japan **1989 year 4 month 16 solstice 9 month 17 Japan **1990 year 4 month 15 solstice 9 month 16 Japan **1991 year 4 month 14 solstice 9 month 15 Japan * Daylight saving time is a “ It's very annoying ” Of things , It greatly increases the complexity of date time processing . Like this soul torture : If your date of birth is 1988-09-11 00:00:00( Last day of daylight saving time ) And put it in the database , Think about it , Is it possible that there will be a problem with the formatting of this date , Is it possible for you to format it as 1988-09-10 23:00:00 Well ? For this torture , I simulated the following code :```java@Testpublic void test5() throws ParseException { String patterStr = "yyyy-MM-dd"; DateFormat dateFormat = new SimpleDateFormat(patterStr); String birthdayStr = "1988-09-11"; // String -> Date -> String Date birthday = dateFormat.parse(birthdayStr); long birthdayTimestamp = birthday.getTime(); System.out.println(" What's Lao Wang's birthday :" + birthday); System.out.println(" The time stamp of Lao Wang's birthday is :" + birthdayTimestamp); System.out.println("============== The program goes through a turnaround , At the same time I Method input parameter passed the date of birth ============="); // String -> Date -> Time stamp -> Date -> String birthday = new Date(birthdayTimestamp); System.out.println(" What's Lao Wang's birthday :" + birthday); System.out.println(" The time stamp of Lao Wang's birthday is :" + dateFormat.format(birthday));}``` This code , In different JDK Version ,** Probably ** There are different results , Those who are interested can copy Go and try it yourself . About JDK Handling daylight saving time ( Summer time in China ) There have been problems and caused bug, At that time, the corresponding JDK The version is `1.8.0_2xx` There's something wrong with the date formatting in the previous version , The version after that seems to be OK . The version information I provide here is for reference only , If you encounter something like case Just upgrade JDK Let's get the latest version , Generally, there will be no problem .> This happens when JDK Between very small version numbers , It's not easy to locate the precise version number boundary , So for reference only, in general , As long as you're using a newer version JDK, Developers don't have to care about daylight saving time , Even though there are still many countries around the world using daylight saving time , We just need to face ** Time zone ** It's OK to do the time conversion .### Date Time zone independence class Date Represents a specific time ** In an instant **, The precision is millisecond . Since it means instant / Moment , Then it must have nothing to do with the time zone , Look at the following code :```java@Testpublic void test6() { String patterStr = "yyyy-MM-dd HH:mm:ss"; Date currDate = new Date(System.currentTimeMillis()); // Beijing time zone DateFormat bjDateFormat = new SimpleDateFormat(patterStr); bjDateFormat.setTimeZone(TimeZone.getDefault()); // New York time zone DateFormat newYorkDateFormat = new SimpleDateFormat(patterStr); newYorkDateFormat.setTimeZone(TimeZone.getTimeZone("America/New_York")); // London time zone DateFormat londonDateFormat = new SimpleDateFormat(patterStr); londonDateFormat.setTimeZone(TimeZone.getTimeZone("Europe/London")); System.out.println(" Milliseconds :" + currDate.getTime() + ", Beijing local time :" + bjDateFormat.format(currDate)); System.out.println(" Milliseconds :" + currDate.getTime() + ", New York local time :" + newYorkDateFormat.format(currDate)); System.out.println(" Milliseconds :" + currDate.getTime() + ", London local time :" + londonDateFormat.format(currDate));}``` Run the program , Output :```java Milliseconds :1610696040244, Beijing local time :2021-01-15 15:34:00 Milliseconds :1610696040244, New York local time :2021-01-15 02:34:00 Milliseconds :1610696040244, London local time :2021-01-15 07:34:00``` That is to say , The same millisecond value , According to the time zone / Different offsets can show the time of many places , That proves it Date Its time zone independence .** Exactly :Date It's from Greenwich mean time ( GMT)1970 year 1 month 1 Japan 0 Point to Date The number of milliseconds passed by the time represented **, It's a number .### Read the string as Date This is a very common requirement in development :client The requester throws you a string like "2021-01-15 18:00:00", And then you need to turn it into Date Type , How to break ? Here comes the question , Throw me a naked string saying 15 On the night of the th 6 Take a little time , How do I know you mean the evening in Beijing 6 Point , It's the night in Tokyo 6 A little bit ? It's a new york night 6 A little bit ?![]( therefore , For date time in string form , It makes sense only if you specify a time zone . That is to say ** String + Time zone ** To know exactly what time it is , Otherwise, there is ambiguity . Maybe you'll say , In my normal development, the front end is to throw a string to me , Then I format it as a Date Type , There is no time zone argument passed in , I haven't seen any problems since I implemented it for so long . As shown below :```java@Testpublic void test7() throws ParseException { String patterStr = "yyyy-MM-dd HH:mm:ss"; // Time string to simulate request arguments String dateStrParam = "2020-01-15 18:00:00"; // The simulation server converts this service into Date Type DateFormat dateFormat = new SimpleDateFormat(patterStr); System.out.println(" The time zone used by the formatter is :" + dateFormat.getTimeZone().getID()); Date date = dateFormat.parse(dateStrParam); System.out.println(date);}``` Run the program , Output :```java The time zone used by the formatter is :Asia/ShanghaiWed Jan 15 18:00:00 CST 2020``` It seems that the result is OK . In fact , That's because by default, you interact with each other and you get a contract : Both sides use Beijing time ( Time zone ), Since it's the same time zone , So there won't be any problem in exchanging what you need . I don't believe you're trying to debug your interface for overseas users ? For formatter , Generally speaking, we don't need to give DateFormat Set the time zone ( Then use the preset time zone ) It can be converted normally . But as a master, you have to be clear , It's clear that this is due to the interactive twin engine design ** There is a contract in the same time zone **.### SimpleDateFormat format Java Middle right Date Input and output of type / format , It is recommended to use DateFormat Instead of using it `toString()` Method .DateFormat Is a time formatter abstract class ,SimpleDateFormat Is its concrete implementation class , Used for ** The language environment is sensitive ** Format and parse dates in the same way . It allows formatting ( date → written words )、 analysis ( written words → date ) And Standardization .> Focus : Sensitive to language environment , That is to say, for the environment Locale、 Time zone TimeZone It's all sensitive . Since it's sensitive , That's it ** Customizable ** For a formatter ,** Pattern **( Template ) It's the key factor , Get to know :** date / Time patterns **: The format pattern consists of the specified string , Unquoted capital / Small letters (A-Z a-z) Represents a specific pattern , Used to express the meaning of a pattern , If you want to ** Output as is ** You can use single quotes '' Wrap it up , Except for the English letters, no other explanation of the original output / matching . Here's the pattern letter it specifies ( Other letters are output as is ): Letter | Meaning | Match type | Example -------- | ----- | ----- | -----**y** | year | Year | 2020,20**M** | month | Month | July; Jul; 07**d** | Days of the month ( It is commonly known as day , Maximum 31) | Number | 10**H** | Hours (0-23) | Number| 0,23**m** | Minutes (0-59) | Number | 30,59**s** | second (0-59) | Number | 30,59--- | --- | --- | yyyy-MM-dd HH:mm:ss( The separator can be any character , Even Chinese characters )**Y** | Year of current week | Year | 2020( Not recommended , Zhou ruo's new year )**S** | Milliseconds (1-999) | Number | 999**a** | am/pm | Text | PM**z** | Time zone | Universal time zone | Pacific Standard Time; PST; GMT-08:00**Z** | Time zone | RFC 822 Time zone | -0800,+0800**X** | Time zone | ISO 8601 Time zone | -08; -0800; -08:00**G** | years | Text | AD( A.D. )、BC( B.c. )**D** | Days of the year (1-366) | Number | 360**w** | Weeks of the year (1-54) | Number | 27**W** | The number of weeks in the month (1-5) | Number | 3**E** | Day of the week | Text | Tuesday; Tue**u** | The number of days of the week (1=Monday...) | Number | 1**k** | Hours (1-24) | Number | Not recommended **K/h** | am/pm The number of hours | Number | General coordination a Using it together, there are some “ special ” The matching type of , Explain as follows :- **Text**: format (Date -> String), If the number of pattern letters is 4 Or more , Then use the full form ; Otherwise , If possible , Use a short or abbreviated form . For analysis (String -> Date), Both forms are the same , It has nothing to do with the number of pattern letters ```java@Testpublic void test9() throws ParseException { String patternStr = "G GG GGGGG E EE EEEEE a aa aaaaa"; Date currDate = new Date(); System.out.println("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Chinese regional model ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓"); System.out.println("====================Date->String===================="); DateFormat dateFormat = new SimpleDateFormat(patternStr, Locale.CHINA); System.out.println(dateFormat.format(currDate)); System.out.println("====================String->Date===================="); String dateStrParam = " A.D. A.D. A.D. Saturday Saturday Saturday Afternoon Afternoon Afternoon "; System.out.println(dateFormat.parse(dateStrParam)); System.out.println("↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ English regional model ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓"); System.out.println("====================Date->String===================="); dateFormat = new SimpleDateFormat(patternStr, Locale.US); System.out.println(dateFormat.format(currDate)); System.out.println("====================String->Date===================="); dateStrParam = "AD ad bC Sat SatUrday sunDay PM PM Am"; System.out.println(dateFormat.parse(dateStrParam));}``` Run the program , Output :```java↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ Chinese regional model ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓====================Date->String==================== A.D. A.D. A.D. Saturday Saturday Saturday Afternoon Afternoon Afternoon ====================String->Date====================Sat Jan 03 12:00:00 CST 1970↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ English regional model ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓====================Date->String====================AD AD AD Sat Sat Saturday PM PM PM====================String->Date====================Sun Jan 01 00:00:00 CST 1970``` Observe the print results , In addition to conforming to the pattern rules , It can also be in **String -> Date When parsing ** Two conclusions are drawn :1. English words , Does not split slot case . Such as SatUrday sunDay No problem , however ** You can't ** There are spelling mistakes 2. If there are more than one part To express a meaning , So last win. Such as Sat SatUrday sunDay The last entry into force is for Locale Geographical arguments , Because there is no format in Chinese 、 Characteristics of abbreviations , So these rules only apply to English regions ( Such as Locale.US take effect )- **Number**: format (Date -> String), The number of pattern letters is numeric 【 Minimum 】 Quantity , Shorter numbers are filled with zeros to this number . For analysis (String -> Date), The number of pattern letters will be ignored , Unless you need to separate two adjacent fields - **Year**: For formatting and parsing , If the number of pattern letters is 4 Or more , Then use a calendar specific long format . Otherwise , Use a calendar specific short or abbreviated form - **Month**: If the number of pattern letters is 3 Or more , Is interpreted as words ; Otherwise , It will be interpreted as a number .- ** Universal time zone **: If the time zone has a name , Such as Pacific Standard Time、PST、CST Wait, then use the name , Otherwise, it will be used GMT Regular strings , Such as :GMT-08:00- **RFC 822 Time zone **: follow RFC 822 Format , Down compatible universal time zone ( Except for the name part )- **ISO 8601 Time zone **: For formatting , If and GMT The offset of is 0( That's Greenwich mean time ), Then generate “Z”; If the number of pattern letters is 1, Then ignore any fraction of the hour . for example , If the mode is “X”, The time zone is “GMT+05:30”, Then generate “+05”. In parsing ,“Z” It is interpreted as UTC Time zone indicator . General time zones are not accepted . If the number of pattern letters is 4 Or more , In construction SimpleDateFormat Or throw when applying mode IllegalArgumentException. - This rule is hard to understand , It is generally not recommended to use this mode in development . If you want to use it, be sure to test it locally SimpleDateFormat It's easy to use , The point is to understand the pattern of its rules . Finally, it's about SimpleDateFormat Let's emphasize these two points again :1. SimpleDateFormat Not a thread security class , Please pay attention to concurrency security when using 2. If you use SimpleDateFormat To format as a non local area ( Presupposition Locale) And then , It must be specified at the time of construction , Such as Locale.US3. For Date Any formatting of type 、 Please use it uniformly SimpleDateFormat## JSR 310 There was once a man who made an interesting vote , Statistics on Java API Of ** Not satisfied ** Degree of . Finally Java Date/Calendar API The second worst ( The first is Java XML/DOM), It has more rotten points , Here are some examples :1. The definitions are not consistent , stay java.util and java.sql It's all in the bag Date Class , And format it / The parsing class goes to java.text Went to the , Schizophrenia 2. java.util.Date The behavior of the class is inconsistent in the design of the modeling date , The defect is obvious . Including variability 、 Bad offset 、 Default value 、 Naming and so on 3. java.util.Date Include both date and time , And its subclasses java.sql.Date But only the date , This is what God inherits ?![](```java@Testpublic void test10() { long currMillis = System.currentTimeMillis(); java.util.Date date = new Date(currMillis); java.sql.Date sqlDate = new java.sql.Date(currMillis); java.sql.Time time = new Time(currMillis); java.sql.Timestamp timestamp = new Timestamp(currMillis); System.out.println("java.util.Date:" + date); System.out.println("java.sql.Date:" + sqlDate); System.out.println("java.sql.Time:" + time); System.out.println("java.sql.Timestamp:" + timestamp);}``` Run the program , Output :```javajava.util.Date:Sat Jan 16 21:50:36 CST 2021java.sql.Date:2021-01-16java.sql.Time:21:50:36java.sql.Timestamp:2021-01-16 21:50:36.733```- International support is not good , For example, cross time zone operation 、 Summer time and so on Java I can't stand such a hard time API 了 , It is in 2014 Years with Java 8 The release of the introduction of a new JSR 310 Date time .JSR-310 From the boutique time bank joda-time make , Solved the problem mentioned above ** All the questions **, It's the whole Java 8 One of the biggest highlights .JSR 310 date / Time ** be-all ** API All in java.time In this bag , There are no exceptions .![]( Of course , This article does not focus on JSR 310 date / Time system , But look at JSR 310 How do date time types handle the above Date The ones that the type encounters case Of .### Time zone / Offset ZoneId stay JDK 8 Before ,Java Use `java.util.TimeZone` To represent the time zone . And in the JDK 8 They used ZoneId Time zone ,ZoneOffset Express UTC The offset . It's worth emphasizing in advance , Time zone and offset are quite different in concept and in practice , Mainly reflected in :1. UTC The offset only records the hours and minutes of the offset , There is no other information . For example :+08:00 It means better than UTC It's early 8 Hours , No geography / Time zone meaning , Correspondingly -03:30 It's just more than UTC It's late 3 An hour and a half 2. Time zones are region specific , It's related to geographical areas ( Including the rules ) Strong ties . For example, the whole of China is called the eighth East District , New York is in west five and so on > There is no daylight saving time in China , The corresponding offset of all eight East regions is always +8; New York has summer time , So its offset may be -4 It could be -5 Oh ** All in all , Time zone is better **. The irritating issue of daylight saving time , If you use UTC It's very troublesome to use offset to express it , Because it's variable : Some periods of the year are offset from the original +1, Some times -1; But if you use ZoneId Time zone is very convenient , For example, New York is west five , You can get the right answer anytime you get the local time , Because it has built-in processing of daylight saving time rules , Which means when +1 When -1 The time zone itself is clear , Unwanted API Callers care about .UTC Offset is more like a way to write the offset value , There is no time zone rule in China ( There is no daylight saving time ) There will be no problems in our country , East eight and UTC+08:00 The effect will always be the same . But in some summer time countries ( Like the United States 、 France and so on ), You can only get the local time according to the time zone . So when you don't know the local rules , It's better to use time zones rather than offsets .#### ZoneId![]( It represents a time zone ID, Such as Europe/Paris. It sets out some rules that can be used to put a Instant Time stamp to local date / Time LocalDateTime. It says time zone ZoneId There are rules , In fact, the actual rules that describe when and how the offset changes are created by `` Define .ZoneId Is just a tool to get the underlying rules ID. The reason for adopting this method , Because ** Rules are defined by the government , And it changes all the time , and ID It's stable **. For API The caller just needs to use this ID( That is to say ZoneId) that will do , And don't care about the lower level of time zone rules ZoneRules, and “ The government ” The thing about the synchronization rule is that the things in its domain are left to it . Such as : The rule of daylight saving time is made by governments , And different countries and years are generally different , It's up to JDK At the bottom ZoneRules The mechanism itself sync, Users don't need to care .ZoneId It's unique in the system , It contains three types of ID:1. The simplest ID Type :ZoneOffset, It consists of 'Z' And with '+' or '-' At the beginning id Make up . Such as :Z、+18:00、-18:002. Another type ID It's an offset style with some form of prefix ID, for example 'GMT+2' or 'UTC+01:00'. Recognizable ( legal ) The prefix is 'UTC', 'GMT' and 'UT'3. The third type is region based ID( It is recommended to use ). Region based ID Must contain two or more characters , And not with 'UTC'、'GMT'、'UT' '+' or '-' The beginning . Region based id Defined by configuration , Such as Europe/Paris A big push on the concept , Let's give a few code examples to experience .1、 Get the system preset ZoneId:```java@Testpublic void test1() { // JDK 1.8 What we did before System.out.println(TimeZone.getDefault()); // JDK 1.8 After that System.out.println(ZoneId.systemDefault());} Output :Asia/Shanghaisun.util.calendar.ZoneInfo[id="Asia/Shanghai",offset=28800000,dstSavings=0,useDaylight=false,transitions=29,lastRule=null]``` The results are the same , All are Asia/Shanghai. Because ZoneId The underlying method is dependency TimeZone, As shown in the picture :![](![](、 Specify the string to get a ZoneId:```java@Testpublic void test2() { System.out.println(ZoneId.of("Asia/Shanghai")); // Report a mistake Unknown time-zone ID: Asia/xxx System.out.println(ZoneId.of("Asia/xxx"));}``` Obviously , This string can't be written casually . That's the problem , What can be written about ? The same ZoneId Provides API For you to get all the available strings id, If you are interested, please try it yourself :```java@Testpublic void test3() { ZoneId.getAvailableZoneIds();}```3、 From the offset, we get a ZoneId:```java@Testpublic void test4() { ZoneId zoneId = ZoneId.ofOffset("UTC", ZoneOffset.of("+8")); System.out.println(zoneId); // It has to be uppercase Z zoneId = ZoneId.ofOffset("UTC", ZoneOffset.of("Z")); System.out.println(zoneId);} Output :UTC+08:00UTC``` Here's the prefix of the first argument , The available values are :"GMT", "UTC", or "UT". Of course, you can also send empty strings , Then go straight back to the second argument ZoneOffset. If none of the above is true, report an error : From the offset ZoneId There are no ready-made time zone rules available inside , Therefore, there may be problems in the conversion of countries with summer camps , This is not generally recommended .4、 Get the time zone from the date :```java@Testpublic void test5() { System.out.println(ZoneId.from(; System.out.println(ZoneId.from(ZoneOffset.of("+8"))); // Report a mistake :java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor: System.out.println(ZoneId.from(; System.out.println(ZoneId.from(;}``` Although the method parameter is TemporalAccessor, But only accept types with time zone ,LocalXXX You can't , Pay attention when using .#### ZoneOffset From Greenwich /UTC Time zone offset for , for example +02:00. It's worth noting that it's inherited from ZoneId, So it can also be used as a ZoneId To use , Of course, you are not recommended to do so , Please use it independently . The time zone offset is the time zone and Greenwich /UTC The time difference between . It's usually a fixed number of hours and minutes . Different parts of the world have different time zone offsets . stay ZoneId Class captures rules about how the offset changes with the place and time of the year ( It's mainly the summer time rule ), So inherited from ZoneId.1、 Minimum / Maximum offset : Because the offset passes in numbers , This is limited ```java@Testpublic void test6() { System.out.println(" Minimum offset :" + ZoneOffset.MIN); System.out.println(" Minimum offset :" + ZoneOffset.MAX); System.out.println(" Center offset :" + ZoneOffset.UTC); // Out of range System.out.println(ZoneOffset.of("+20"));} Output : Minimum offset :-18:00 Minimum offset :+18:00 Center offset :Zjava.time.DateTimeException: Zone offset hours not in valid range: value 20 is not in the range -18 to 18```2、 The offset is constructed by time, minute and second ( Easy to use , Recommendation ):```java@Testpublic void test7() { System.out.println(ZoneOffset.ofHours(8)); System.out.println(ZoneOffset.ofHoursMinutes(8, 8)); System.out.println(ZoneOffset.ofHoursMinutesSeconds(8, 8, 8)); System.out.println(ZoneOffset.ofHours(-5)); // Specify an exact number of seconds Get instance item ( Sometimes it's useful ) System.out.println(ZoneOffset.ofTotalSeconds(8 * 60 * 60));}// Output :+08:00+08:08+08:08:08-05:00+08:00``` It seems that , The offset can be accurate to seconds , It's just that it's generally accurate to the minute, and it's at the top .##### Set the default time zone ZoneId There's no way to set a preset time zone , But the article shows that ZoneId Getting the default time zone depends on `TimeZone.getDefault()` Method , Therefore, setting the preset time zone completely follows TimeZone In this way ( There are three ways , Remember ?).### Irritating daylight saving time because of the existence of daylight saving time rules , Let the operation date / The complexity of time is greatly increased . But it's OK JDK Try to mask the impact of these rules on users . therefore : Time zone is recommended (ZoneId) Conversion date / Time , Generally, it is not recommended to use offset ZoneOffset Go ahead , So there won't be any worries about daylight saving time .### JSR 310 Time zone correlation java.util.Date It has time zone independence , The drawback is that when it comes to international time conversion and other needs , Use Date It's very inconvenient to deal with it .JSR 310 Solved Date There are a series of problems : To date 、 Time is expressed separately (LocalDate、LocalTime、LocalDateTime), Local time and time with time zone are managed separately .LocalXXX It means local time , That is to say, at present JVM Time in your time zone ;ZonedXXX It means that it is a ** With a time zone ** Date time of , They can easily transform each other .```java@Testpublic void test8() { // Local date / Time System.out.println("================ Local time ================"); System.out.println(; System.out.println(; System.out.println(; // Time zone time System.out.println("================ Time with time zone ZonedDateTime================"); System.out.println(; // Use the system time zone System.out.println("America/New_York"))); // Set your own time zone System.out.println(; // Set your own time zone System.out.println("================ Time with time zone OffsetDateTime================"); System.out.println(; // Use the system time zone System.out.println("America/New_York"))); // Set your own time zone System.out.println(; // Set your own time zone }``` Run the program , Output :```java================ Local time ================2021-01-1709:18:40.7032021-01-17T09:18:40.703================ Time with time zone ZonedDateTime================2021-01-17T09:18:40.704+08:00[Asia/Shanghai]2021-01-16T20:18:40.706-05:00[America/New_York]2021-01-17T01:18:40.709Z================ Time with time zone OffsetDateTime================2021-01-17T09:18:40.710+08:002021-01-16T20:18:40.710-05:002021-01-17T01:18:40.710Z``` The output of local time is very “ Be clean ”, It can be used directly to display . The time with time zone shows which time zone the time represents , After all, there's no point in not specifying a time zone .LocalXXX Because it's time zone independent , So it doesn't represent a moment / Moment . in addition , About LocalDateTime、OffsetDateTime、ZonedDateTime Cross time zone conversion of the three , And their details , Because the content is too much in the following special article , Keep an eye on .### Read the string as JSR 310 Type a separate date time type string, such as 2021-05-05T18:00-04:00 It doesn't make any sense , Because there's no time zone to be sure it represents that moment , It's a theory, and of course it suits JSR 310 Types . Encountered a date time format string , To analyze it, there are two cases :1. No time zone / Offset string : If you ignore it, you can't change it , What do you want ** Set up a time zone **( The time zone is usually preset by the system ), Use LocalDateTime To analyze ```java@Testpublic void test11() { String dateTimeStrParam = "2021-05-05T18:00"; LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStrParam); System.out.println(" After analysis :" + localDateTime);} Output : After analysis :2021-05-05T18:00```2. With time zone / Character string of offset :```java@Testpublic void test12() { // With offset Use OffsetDateTime String dateTimeStrParam = "2021-05-05T18:00-04:00"; OffsetDateTime offsetDateTime = OffsetDateTime.parse(dateTimeStrParam); System.out.println(" After analyzing with offset :" + offsetDateTime); // With time zone Use ZonedDateTime dateTimeStrParam = "2021-05-05T18:00-05:00[America/New_York]"; ZonedDateTime zonedDateTime = ZonedDateTime.parse(dateTimeStrParam); System.out.println(" After parsing with time zone :" + zonedDateTime);} Output : After analyzing with offset :2021-05-05T18:00-04:00 After parsing with time zone :2021-05-05T18:00-04:00[America/New_York]``` Please note ** After parsing with time zone ** This result : The string argument offset is clearly -05, For Mao to ZonedDateTime The post offset becomes -04 Well ??? Here I deliberately built this one case Get your attention , I'll explain the result as follows :![]( As shown in the picture , stay 2021.03.14 - 2021.11.07 Period , The offset in New York is -4, The rest of the time is -5. The date of this example is 2021-05-05 In daylight saving time , So the offset is -4, That's why what you're showing says -5 In the end, it became -4.### JSR 310 Format for JSR 310 Formatting of date time type / analysis , There's a special class `java.time.format.DateTimeFormatter` To deal with .DateTimeFormatter It's also an immutable class , So it's thread safe , Than SimpleDateFormat It's much more reliable . In addition, it also built a lot of formatting templates ** For example ** For use , Form like : formatter | Example -------- | -----ofLocalizedDate(dateStyle) | '2021-01-03'ofLocalizedTime(timeStyle) | '10:15:30'ofLocalizedDateTime(dateTimeStyle) | '3 Jun 2021 11:05:30'**ISO_LOCAL_DATE** | '2021-12-03'**ISO_LOCAL_TIME** | '10:15:30'**ISO_LOCAL_DATE_TIME** | '2021-12-03T10:15:30'ISO_OFFSET_DATE_TIME | '2021-12-03T10:15:30+01:00'ISO_ZONED_DATE_TIME | '2021-12-03T10:15:30+01:00[Europe/Paris]'```java@Testpublic void test13() { System.out.println(DateTimeFormatter.ISO_LOCAL_DATE.format(; System.out.println(DateTimeFormatter.ISO_LOCAL_TIME.format(; System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(;} Output :2021-01-1722:43:21.3982021-01-17T22:43:21.4``` If you want to customize the mode pattern, and Date It can also specify any pattern ** date / Time patterns **. Because this article is in Date The section details the date / Time patterns , What do the letters mean and how to use them , I won't repeat it here .> Although DateTimeFormatter The mode of support is better than Date Slightly increased , But it's roughly the same , I don't think we need to spend any more energy on this . If you really need to check the official website, it's not too late ```java@Testpublic void test14() { DateTimeFormatter formatter = DateTimeFormatter.ofPattern(" The first Q quarter yyyy-MM-dd HH:mm:ss", Locale.US); // Format output System.out.println(formatter.format(; // analysis String dateTimeStrParam = " The first 1 quarter 2021-01-17 22:51:32"; LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStrParam, formatter); System.out.println(" The result of the analysis :" + localDateTime);}```Q/q: quarter , Such as 3; 03; Q3; 3rd quarter.## Best practices - ** Discard Date, Embrace JSR 310** When it comes to JSR 310 date / I'll call in time , Keep the routine, I'll keep on saying : Give up Date Even disabled Date, Use JSR 310 date / Time is up , It's the best practice of date time processing . in addition , About setting time zone during use ( When the time zone is preset ) There is still a set of best practices in my mind , Here to share with you :- ** Always explicitly specify the time zone you need , Even if you want to get a preset time zone **```java// Mode one : Common practice;// Mode two : Best practices;``` The code two is as like as two peas . But way two is best practice . The reason is that : This allows the code to have ** Clear intent **, Eliminate the possibility of ambiguity , Even if you get the preset time zone . Take way one , It's where the intention is not clear : In the end, the coder forgot to specify the time zone , Or just want to use the preset time zone ? The answer can't be determined without reading the context , This leads to unnecessary communication and maintenance costs . So even if you want to get the preset time zone , Please also use ZoneId.systemDefault() Write it down .- ** Use JVM Be careful of your default time zone , It is recommended that the time zone and the current session remain bound ** This best practice can be used in special situations . The reason for this is :JVM The default time zone of is set by static method TimeZone#setDefault() It can be set globally , therefore JVM Any thread of can change the preset time zone at will . When it comes to time processing code ** Very sensitive to time zones ** And then , The best practice is that you link time zone information to the current session , So that you don't have to be potentially affected by other threads , Ensures robustness .> Explain : The session may just be the current request , It could be a Session, Specifically case Specific analysis # Summarize and pass [ Last article ]( Foreshadowing the concept of date and time , With the demonstration of practical code in this paper , To get through Java There is no problem with date and time . The content of the two articles is more , The amount of information is relatively large , It takes time to digest . On the one hand, I suggest you search and keep them as reference books , On the other hand, more practice is suggested , Only by writing more code can we have a deeper understanding . Later ** Reuse 3 -4 An article ** For the details of the previous two articles 、 Use scenarios to supplement , For example, how to match ZoneId and Offset Correspondence of ,LocalDateTime、OffsetDateTime、ZonedDateTime Cross time zone transfer problem 、 stay Spring MVC Best practices used in scenarios, etc , Please pay attention , Make progress together .## After reading this article, I don't necessarily understand it , If you understand it, you don't have to . Come , At the end of the article 3 A question to help you review :1. Date How type deals with daylight saving time ?2. ZoneId and ZoneOffset What's the difference ?3. Usually, if the project encounters date and time processing , What are the best practices ?## Recommended reading [**GMT UTC CST ISO Daylight time Time stamp , What kind of ghosts are they ?**]( Follow me and share 、 Grow up , Refuse to hide . Concern 【BAT The Utopia of 】 Reply key ** Column ** Yes Spring Technology stack 、 Media software and other small and beautiful pure original Columns . This article has been []( Included . This article belongs to the column :**JDK Date time **, You can get all the content by answering the column name in the background of the company .A Brother (YourBatman):Spring Framework/Boot Open source contributors ,Java Architect . Very focused ** Basic training **, Believe that the superstructure depends on the foundation , Only a solid foundation can revitalize the vitality of programmers . The article is characterized by reconstructing the knowledge system in the form of small and beautiful columns , To spin a cocoon , Committed to do everyone can understand the best column series . You can add my friends (**fsx1056342982**) Let's share !![](

  1. 【计算机网络 12(1),尚学堂马士兵Java视频教程
  2. 【程序猿历程,史上最全的Java面试题集锦在这里
  3. 【程序猿历程(1),Javaweb视频教程百度云
  4. Notes on MySQL 45 lectures (1-7)
  5. [computer network 12 (1), Shang Xuetang Ma soldier java video tutorial
  6. The most complete collection of Java interview questions in history is here
  7. [process of program ape (1), JavaWeb video tutorial, baidu cloud
  8. Notes on MySQL 45 lectures (1-7)
  9. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  10. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  11. 精进 Spring Boot 03:Spring Boot 的配置文件和配置管理,以及用三种方式读取配置文件
  12. Refined spring boot 03: spring boot configuration files and configuration management, and reading configuration files in three ways
  13. 【递归,Java传智播客笔记
  14. [recursion, Java intelligence podcast notes
  15. [adhere to painting for 386 days] the beginning of spring of 24 solar terms
  16. K8S系列第八篇(Service、EndPoints以及高可用kubeadm部署)
  17. K8s Series Part 8 (service, endpoints and high availability kubeadm deployment)
  18. 【重识 HTML (3),350道Java面试真题分享
  19. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  20. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  21. [re recognize HTML (3) and share 350 real Java interview questions
  22. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  23. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  24. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  25. RPC 1: how to develop RPC framework from scratch
  26. 造轮子系列之RPC 1:如何从零开始开发RPC框架
  27. RPC 1: how to develop RPC framework from scratch
  28. 一次性捋清楚吧,对乱糟糟的,Spring事务扩展机制
  29. 一文彻底弄懂如何选择抽象类还是接口,连续四年百度Java岗必问面试题
  30. Redis常用命令
  31. 一双拖鞋引发的血案,狂神说Java系列笔记
  32. 一、mysql基础安装
  33. 一位程序员的独白:尽管我一生坎坷,Java框架面试基础
  34. Clear it all at once. For the messy, spring transaction extension mechanism
  35. A thorough understanding of how to choose abstract classes or interfaces, baidu Java post must ask interview questions for four consecutive years
  36. Redis common commands
  37. A pair of slippers triggered the murder, crazy God said java series notes
  38. 1、 MySQL basic installation
  39. Monologue of a programmer: despite my ups and downs in my life, Java framework is the foundation of interview
  40. 【大厂面试】三面三问Spring循环依赖,请一定要把这篇看完(建议收藏)
  41. 一线互联网企业中,springboot入门项目
  42. 一篇文带你入门SSM框架Spring开发,帮你快速拿Offer
  43. 【面试资料】Java全集、微服务、大数据、数据结构与算法、机器学习知识最全总结,283页pdf
  44. 【leetcode刷题】24.数组中重复的数字——Java版
  45. 【leetcode刷题】23.对称二叉树——Java版
  46. 【leetcode刷题】22.二叉树的中序遍历——Java版
  47. 【leetcode刷题】21.三数之和——Java版
  48. 【leetcode刷题】20.最长回文子串——Java版
  49. 【leetcode刷题】19.回文链表——Java版
  50. 【leetcode刷题】18.反转链表——Java版
  51. 【leetcode刷题】17.相交链表——Java&python版
  52. 【leetcode刷题】16.环形链表——Java版
  53. 【leetcode刷题】15.汉明距离——Java版
  54. 【leetcode刷题】14.找到所有数组中消失的数字——Java版
  55. 【leetcode刷题】13.比特位计数——Java版
  56. oracle控制用户权限命令
  57. 三年Java开发,继阿里,鲁班二期Java架构师
  58. Oracle必须要启动的服务
  59. 万字长文!深入剖析HashMap,Java基础笔试题大全带答案
  60. 一问Kafka就心慌?我却凭着这份,图灵学院vip课程百度云