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

YourBatman 2021-01-21 12:06:11
complete network thoroughly understand java


Preface

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 saving 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 it

First concept , This article is a practical operation , They complement each other , Be short of one cannot . There are many contents in this article , Longer text , Expected to exceed 2w word , It's designed to help you completely Java Processing of date and time , I suggest you collect it , Keep it for reference .

Outline of this article

Version conventions

  • JDK:8

Text

So many concepts have been laid out above , As a Javaer Of course, they are the most concerned “ Concept ” stay Java The landing in the garden . How to deal with time in daily work ? use Date still JDK 8 Date time after API? How to solve the big problems such as cross time zone conversion .A Elder brother has always been in charge of production and maintenance , Kill and bury , So this article takes you to appreciate it ,Java How to achieve GMT and UTC Of ?

as everyone knows ,JDK In version 8 As a boundary , There are two sets of processing dates / The time of the API:

Although I always encourage abandonment Date The support is only used in the project JSR 310 Date time type , But what? , because Date There is 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 represent a date + The type of time , Even though it's very old , And the responsibilities of this kind are not single , It is very inconvenient to use , However, due to the historical reasons of more than ten or twenty years , Its vitality is still tenacious , Huge number of users .

Let's meet first Date, Take a look at the output of this example :

@Test
public 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 :

Fri Jan 15 10:22:34 CST 2021
2021-1-15 10:22:34
15 Jan 2021 02:22:34 GMT

first : The standard UTC Time (CST That's the offset +0800)
the second : Local time , Time format displayed according to local time zone
Third :GTM Time , That's Greenwich time , You can see it's early in the morning 2 spot ( Beijing time is in the morning 10 Oh, oh. )

the second 、 The third is actually JDK 1.1 It's all marked as @Deprecated Out of date , Basically no reuse . If necessary, switch to local time or GTM Time output , Please use the formatter java.text.DateFormat To deal with .

The time zone / Offset TimeZone

stay JDK8 Before ,Java The time zone and offset are used java.util.TimeZone To represent the .

In general , Use static methods TimeZone#getDefault() You can get the current JVM The time zone in which you are running , 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 it With time zone Time conversion of , for example : The return value of the interface should include both the display time and Beijing time , New York time, too . 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 :

@Test
public void test2() {
String patternStr = "yyyy-MM-dd HH:mm:ss";
// Beijing time. (new This is the default 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 :

 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

So here comes the question , How do you know how to get the time zone of New York America/New_York This zoneId Well ? Can I just write a string ?

The answer is of course not , There are rules to follow . Next, I will introduce two kinds of search methods zoneId The way , choose any as you like :

Mode one : use Java The program takes all available zoneId Print out , Then look it up

@Test
public 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 :/ State before ,/ Indicates the name of the city ):

 You can use zoneId total :628
Africa/Abidjan
Africa/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 // The European / London
...
Etc/GMT
Etc/GMT+0
Etc/GMT+1
...

It's worth noting that there is not 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 Generally, there will be no change

Mode two
zoneId The list is jre Maintenance of a text file , The path is you JDK/JRE Installation path for . The address in .\jre\lib The name of the directory is not found tzmappings In the text file of . Open this file ctrl + f Searching can also achieve the purpose of searching .

These two kinds of houses can help you find them ZoneId It's easy to look up in your dictionary , But there is another situation : What about the current city , stay tzmappings There's nothing in the file ( For example, not included ), Then we need 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 was 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

@Test
public 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 :

GMT+08:00 // The effect is equivalent to Asia/Shanghai
Asia/Shanghai
GMT-05:00 // The effect is equivalent to America/New_York
America/New_York

It is worth noting that , You can only use GMT+08:00, But can't use UTC+08:00, The reasons are explained below .

Set the default time zone

Generally speaking ,JVM Where to run , What is the default time zone . For domestic programmers , Generally, we only touch the East eighth district , It's Beijing time ( Local time ). As international cooperation becomes closer and closer , Most of the time, it needs date and time internationalization , Take a very practical example : Deployment of the same application in alicloud 、 stay AWS( overseas ) We have also deployed one for overseas users , here The same code Deployed in different time zones , How to deal with it ?

If the time zone is different , So it will affect the running result of the program , It's easy to make mistakes in computational logic , It's probably going to be a mess .Java Let's do it in a variety of ways Manual Set up / Change the default time zone :

  1. API The way : Force time zone to Beijing TimeZone.setDefault(TimeZone.getDefault().getTimeZone("GMT+8"));
  2. JVM Parameters of the way :-Duser.timezone=GMT+8
  3. Operation and maintenance setting mode : Set the operating system host time zone to Beijing time zone , This is the recommended way , Can be totally insensitive to developers , It also facilitates the unified management of operation and maintenance

As far as I know , Many companies in Alibaba cloud 、 Tencent cloud 、 When deploying applications on cloud hosts at home and abroad , All of them adopt operation and maintenance to set up a unified time zone : China time zone , It's managed in this way , This eliminates the inconsistency of the default time zone for the program , Developer friendly .

Annoying daylight saving time

You know what? , China used to use daylight saving time .

What is daylight saving time ? Poke it here

What's the closest to now 1986 - 1991 Summer time was used 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 When the check ):
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 good time “ It's very annoying ” Things that are , 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 stored 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 :

@Test
public void test5() throws ParseException {
String patterStr = "yyyy-MM-dd";
DateFormat dateFormat = new SimpleDateFormat(patterStr);
String birthdayStr = "1988-09-11";
// character string -> Date -> character string
Date birthday = dateFormat.parse(birthdayStr);
long birthdayTimestamp = birthday.getTime();
System.out.println(" What's Lao Wang's birthday :" + birthday);
System.out.println(" What is the time stamp of Lao Wang's birthday :" + birthdayTimestamp);
System.out.println("============== The program went through a turnaround , At the same time as I Method input parameter passed the date of birth =============");
// character string -> Date -> Time stamp -> Date -> character string
birthday = new Date(birthdayTimestamp);
System.out.println(" What's Lao Wang's birthday :" + birthday);
System.out.println(" What is the time stamp of Lao Wang's birthday :" + dateFormat.format(birthday));
}

This code , In different JDK Run... Under version , Probably There are different results , If you are interested, you can copy Go and try it yourself .

About JDK Processing daylight saving time ( Summer time in China ) There have been problems and causes bug, 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 , In case of similar problems case Just upgrade JDK Let's get the latest version , Generally, there will be no problem .

What's going on here JDK Very small version numbers , It's not easy to locate the precise version number limit , So for reference only

in general , As long as you are 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 The time zone It's OK to change time .

Date Time zone independence

class Date Represents a specific time Instantaneous , Precision in milliseconds . Since it means instant / moment , Then it must have nothing to do with the time zone , Look at the code below :

@Test
public 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(" Number of milliseconds :" + currDate.getTime() + ", Beijing local time :" + bjDateFormat.format(currDate));
System.out.println(" Number of milliseconds :" + currDate.getTime() + ", New York local time :" + newYorkDateFormat.format(currDate));
System.out.println(" Number of milliseconds :" + currDate.getTime() + ", London local time :" + londonDateFormat.format(currDate));
}

Run the program , Output :

 Number of milliseconds :1610696040244, Beijing local time :2021-01-15 15:34:00
Number of milliseconds :1610696040244, New York local time :2021-01-15 02:34:00
Number of milliseconds :1610696040244, London local time :2021-01-15 07:34:00

in other words , Same millisecond value , According to the time zone / Different offsets can show the time of many places , This proves Date Its time zone independence .

To be exact :Date The object is from Greenwich mean time ( GMT)1970 year 1 month 1 Japan 0 Point to the Date The number of milliseconds elapsed at the time represented , It's a number .

Read the string as Date type

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 deal with it ?

The problem is coming. , Throw me a string naked and say it's 15 No. In the evening 6 Point time , How do I know you mean the evening in Beijing 6 spot , It's the night in Tokyo 6 How about it? ? Or new york night 6 How about it? ?

therefore , For date time in string form , It makes sense only if you specify a time zone . in other words character string + The time zone To know exactly when it is , Otherwise, there is ambiguity .

Maybe you will , 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 parameter passed in , I haven't seen any problems since I've been running for so long . As shown below :

@Test
public void test7() throws ParseException {
String patterStr = "yyyy-MM-dd HH:mm:ss";
// Time string to simulate request parameters
String dateStrParam = "2020-01-15 18:00:00";
// The simulation server converts this service to Date type
DateFormat dateFormat = new SimpleDateFormat(patterStr);
System.out.println(" What is the time zone for the formatter :" + dateFormat.getTimeZone().getID());
Date date = dateFormat.parse(dateStrParam);
System.out.println(date);
}

Run the program , Output :

 What is the time zone for the formatter :Asia/Shanghai
Wed Jan 15 18:00:00 CST 2020

It seems that the result is OK . in fact , That's because by default, you have a contract with both sides : Both parties use Beijing time ( The 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 give your interface to overseas users for debugging ?

For formatters , Generally speaking, we don't need to give DateFormat Set time zone ( Then use the default time zone ) It can be converted normally . But as a master, you have to be clear , Clearly know that this is due to interactive double default There is a contract in the same time zone .

SimpleDateFormat format

Java Chinese vs Date Input and output of type / format , Recommended DateFormat Instead of using it toString() Method .

DateFormat Is a time formatter abstract class ,SimpleDateFormat Is its concrete implementation class , Used to Language environment sensitivity Format and parse dates in the same way . It allows formatting ( date → Text )、 analysis ( Text → date ) And standardization .

Focus on : Sensitive to language environment , That is to say, to the environment Locale、 The time zone TimeZone It's all sensitive . Since it's sensitive , That's it Customizable

For a formatter , Pattern ( Template ) Is the key factor , Get to know :

date / Time pattern
The format pattern consists of the specified string , Unquoted capitalization / Lowercase letters (A-Z a-z) Represents a specific pattern , Used to express the meaning of a pattern , If you want to Original output You can use single quotes '' wrap up , Except for the English letters, no other explanation of the original output / matching . Here is the pattern letter it specifies ( Other letters output as is ):

Letter meaning Match type Example
y year Year 2020,20
M month Month July; Jul; 07
d Days of the month ( Commonly known as day , Maximum 31) Number 10
H Hours (0-23) Number 0,23
m minute (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 Number of milliseconds (1-999) Number 999
a am/pm Text PM
z The time zone Universal time zone Pacific Standard Time; PST; GMT-08:00
Z The time zone RFC 822 The time zone -0800,+0800
X The time zone ISO 8601 The 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 The number of weeks in a year (1-54) Number 27
W Number of weeks in the month (1-5) Number 3
E Day of the week Text Tuesday; Tue
u Day 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 Use it together

There are some problems in this table “ special ” Match type for , Explain as follows :

  • Text: format (Date -> String), If the number of pattern letters is 4 One or more , Use the full form ; otherwise , If possible , Use short or abbreviated forms . For parsing (String -> Date), Both forms are the same , It has nothing to do with the number of pattern letters
@Test
public 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 :

↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 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 still be in String -> Date When parsing Two conclusions are drawn :

  1. English words , No partition case . Such as SatUrday sunDay No problem , however You can't There are spelling mistakes
  2. If there are multiple part To express an idea , that last win. Such as Sat SatUrday sunDay The last one comes into effect

about Locale Regional parameters , Because there is no format in Chinese 、 Characteristics of abbreviations , Therefore, these rules only apply to English speaking regions ( Such as Locale.US take effect )

  • Number: format (Date -> String), The number of pattern letters is numeric 【 Minimum 】 Number , Shorter numbers are filled with zeros to this number . For parsing (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 One or more , A calendar specific long format is used . otherwise , Use a calendar specific short or abbreviated form
  • Month: If the number of pattern letters is 3 One or more , Is interpreted as text ; 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 The string of the rule , Such as :GMT-08:00
  • RFC 822 The time zone : follow RFC 822 Format , Downward compatible universal time zone ( Except the name part )
  • ISO 8601 The time zone : For formatting , If the GMT The offset value of is 0( That's Greenwich mean time ), Generate a “Z”; If the number of pattern letters is 1, Any fraction of the hour is ignored . for example , If the mode is “X”, The time zone is “GMT+05:30”, Generate a “+05”. When parsing ,“Z” Is interpreted as UTC Time zone indicator . General time zones are not accepted . If the number of pattern letters is 4 One or more , In the structure SimpleDateFormat Or application mode IllegalArgumentException.
    • It's hard to understand this rule , 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 key is to understand its rules and patterns . Last on SimpleDateFormat Let's emphasize these two points again :

  1. SimpleDateFormat Is not a thread safe class , Please pay attention to concurrency security when using
  2. If you use SimpleDateFormat To format as a non local region ( Default Locale) Words , It must be specified at the time of construction , Such as Locale.US
  3. about Date Any formatting of type 、 Please use it uniformly SimpleDateFormat

JSR 310 type

There was a man who made an interesting vote , Statistical right Java API Of dissatisfied Degree of . Final Java Date/Calendar API The second worst ( The first one is bad 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 analytic class ran 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 , Obvious defects . Including variability 、 Bad offset 、 The default value is 、 Naming and so on
  3. java.util.Date Include both date and time , And its subclass java.sql.Date But only the date , What kind of divine inheritance is this ?

@Test
public 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 :

java.util.Date:Sat Jan 16 21:50:36 CST 2021
java.sql.Date:2021-01-16
java.sql.Time:21:50:36
java.sql.Timestamp:2021-01-16 21:50:36.733
  • Internationalization is not well supported , For example, cross time zone operation 、 Summer time and so on

Java I can't stand such a hard time API 了 , So in 2014 Years as Java 8 The release of introduced a new JSR 310 Date time .JSR-310 From the boutique time library joda-time make , Solve the above problems All questions , As a whole Java 8 One of the biggest highlights .

JSR 310 date / Time be-all API All in java.time It's in this bag , No exceptions .

Of course , This article does not focus on discussion JSR 310 date / Time system , But look at JSR 310 How do date time types handle the above Date The types encountered case Of .

The time zone / Offset ZoneId

stay JDK 8 Before ,Java Use java.util.TimeZone To represent the time zone . And in the JDK 8 We use the ZoneId Time zone ,ZoneOffset Express UTC The offset .

It is 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 instance :+08:00 It means better than UTC It's early 8 Hours , There is no geography / Time zone meaning , Corresponding -03:30 It's just more than UTC It's late 3 One and a half hours
  2. Time zones are region specific , It's not the same as geographical areas ( Including rules ) Strong binding . 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

Taken together , Better time zone . The irritating issue of daylight saving time , If you use UTC It's a lot of trouble to express the offset , Because it's variable : Some periods of the year are offset from the original +1, Certain periods -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 is clear , Unwanted API Callers care .

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 district and UTC+08:00 The effect will always be the same . But in some summer time countries ( Such as 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 java.time.zone.ZoneRules Definition .ZoneId It's just a tool to get the underlying rules ID. The reason for this approach , Because Rules are defined by the government , And it changes all the time , and ID It is stable. .

about API This is all the caller needs to use 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 you JDK At the bottom ZoneRules The mechanism itself sync, Users don't need to care .

ZoneId It's unique in the system , It consists of three types ID:

  1. The simplest ID type :ZoneOffset, It consists of 'Z' And with '+' or '-' At the beginning id form . Such as :Z、+18:00、-18:00
  2. Another type of 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( Recommended ). Region based ID Must contain two or more characters , And not with 'UTC'、'GMT'、'UT' '+' or '-' start . Region based id Defined by configuration , Such as Europe/Paris

A big push on the concept , Let's give a few code examples to feel it .

1、 Get the system default ZoneId:

@Test
public void test1() {
// JDK 1.8 What we did before
System.out.println(TimeZone.getDefault());
// JDK 1.8 What to do after
System.out.println(ZoneId.systemDefault());
}
Output :
Asia/Shanghai
sun.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 bottom layer of a method is dependency TimeZone, Pictured :

2、 Specifies the string to get a ZoneId:

@Test
public void test2() {
System.out.println(ZoneId.of("Asia/Shanghai"));
// Report errors :java.time.zone.ZoneRulesException: Unknown time-zone ID: Asia/xxx
System.out.println(ZoneId.of("Asia/xxx"));
}

Obviously , This string can't be written casually . So here comes the question , What can be written ? alike ZoneId Provides API For you to get all the available strings id, If you are interested, please try it yourself :

@Test
public void test3() {
ZoneId.getAvailableZoneIds();
}

3、 We get one from the offset ZoneId:

@Test
public void test4() {
ZoneId zoneId = ZoneId.ofOffset("UTC", ZoneOffset.of("+8"));
System.out.println(zoneId);
// It must be in capital Z
zoneId = ZoneId.ofOffset("UTC", ZoneOffset.of("Z"));
System.out.println(zoneId);
}
Output :
UTC+08:00
UTC

Here is the prefix of the first parameter , The available values are :"GMT", "UTC", or "UT". Of course, it can also pass empty strings , Then return the second parameter directly ZoneOffset. If none of the above is true, report an error

Be careful : According to the offset ZoneId There are no ready-made time zone rules available internally , So for countries with summer camps, the transition may be problematic , This is generally not recommended .

4、 Get the time zone from the date :

@Test
public void test5() {
System.out.println(ZoneId.from(ZonedDateTime.now()));
System.out.println(ZoneId.from(ZoneOffset.of("+8")));
// Report errors :java.time.DateTimeException: Unable to obtain ZoneId from TemporalAccessor:
System.out.println(ZoneId.from(LocalDateTime.now()));
System.out.println(ZoneId.from(LocalDate.now()));
}

Although the method into the parameter is TemporalAccessor, But only types with time zone are accepted ,LocalXXX You can't , Pay attention when using .

ZoneOffset

Distance to 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 an example ZoneId To use the , Of course, it's not recommended , Please use it independently .

The time zone offset is the time zone and Greenwich /UTC 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 to capture 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 is a number , This is limited

@Test
public 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 :Z
java.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 , recommend ):

@Test
public 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 ( 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 , 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 is no way to set the default time zone , But we can see from the article ZoneId To get the default time zone, the underlying dependency is TimeZone.getDefault() Method , So setting the default time zone completely follows TimeZone In this way ( There are three ways , Do you remember? ?).

Annoying daylight saving time

Because of the existence of daylight saving time rules , Let operation date / The time complexity is greatly increased . But also good JDK Try to shield the impact of these rules on users . therefore : Time zone recommended (ZoneId) Date of conversion / 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 is time zone independent , 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 It's solved Date There are a series of problems : Right date 、 Time is expressed separately (LocalDate、LocalTime、LocalDateTime), Local time and time with time zone are managed separately .LocalXXX Represents local time , That is to say, the current situation JVM Time in your time zone ;ZonedXXX It means a With time zone Date time of , They can easily transform each other .

@Test
public void test8() {
// Local date / Time
System.out.println("================ Local time ================");
System.out.println(LocalDate.now());
System.out.println(LocalTime.now());
System.out.println(LocalDateTime.now());
// Time zone time
System.out.println("================ Time with time zone ZonedDateTime================");
System.out.println(ZonedDateTime.now()); // Use system time zone
System.out.println(ZonedDateTime.now(ZoneId.of("America/New_York"))); // Specify your own time zone
System.out.println(ZonedDateTime.now(Clock.systemUTC())); // Specify your own time zone
System.out.println("================ Time with time zone OffsetDateTime================");
System.out.println(OffsetDateTime.now()); // Use system time zone
System.out.println(OffsetDateTime.now(ZoneId.of("America/New_York"))); // Specify your own time zone
System.out.println(OffsetDateTime.now(Clock.systemUTC())); // Specify your own time zone
}

Run the program , Output :

================ Local time ================
2021-01-17
09:18:40.703
2021-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:00
2021-01-16T20:18:40.710-05:00
2021-01-17T01:18:40.710Z

The output of local time is very good “ clean ”, It can be directly used for 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 is 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 detailed explanation , 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 Type .

A date time format string was encountered , To analyze it, there are two cases :

  1. No time zone / Offset string : Or ignore it and say you can't change , Or Set a time zone ( Generally, the system default time zone is used ), Use LocalDateTime Parsing
@Test
public void test11() {
String dateTimeStrParam = "2021-05-05T18:00";
LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStrParam);
System.out.println(" After the parsing :" + localDateTime);
}
Output :
After the parsing :2021-05-05T18:00
  1. Time zone word / Character string of offset :
@Test
public void test12() {
// With offset Use OffsetDateTime
String dateTimeStrParam = "2021-05-05T18:00-04:00";
OffsetDateTime offsetDateTime = OffsetDateTime.parse(dateTimeStrParam);
System.out.println(" After analysis 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 analysis with offset :2021-05-05T18:00-04:00
After parsing with time zone :2021-05-05T18:00-04:00[America/New_York]

Please note that After parsing with time zone This result : The string parameter offset is explicitly -05, For wool to ZonedDateTime The post offset becomes -04 Well ???

Here's one I built on purpose case To get your attention , I'll explain the result as follows :

Pictured , stay 2021.03.14 - 2021.11.07 period , What's the offset for New York -4, The rest of the time -5. The date of this example is 2021-05-05 In daylight saving time , So the offset is -4, That's why what you show is written -5 In the end, it did -4.

JSR 310 format

in the light of JSR 310 Format date time type / analysis , There is a special class java.time.format.DateTimeFormatter Used for processing .

DateTimeFormatter It is also an immutable class , So it's thread safe , Than SimpleDateFormat It's much more reliable . In addition, it also has a lot of built-in formatting templates 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]'
@Test
public void test13() {
System.out.println(DateTimeFormatter.ISO_LOCAL_DATE.format(LocalDate.now()));
System.out.println(DateTimeFormatter.ISO_LOCAL_TIME.format(LocalTime.now()));
System.out.println(DateTimeFormatter.ISO_LOCAL_DATE_TIME.format(LocalDateTime.now()));
}
Output :
2021-01-17
22:43:21.398
2021-01-17T22:43:21.4

If you want to customize the mode pattern, and Date It can also specify any pattern date / Time pattern . Since this paper Date The date section details the date / Time pattern , What do the letters mean and how to use them , I won't repeat it here .

although DateTimeFormatter Supported mode ratio 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 is not too late

@Test
public 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(LocalDateTime.now()));
// analysis
String dateTimeStrParam = " The first 1 quarter 2021-01-17 22:51:32";
LocalDateTime localDateTime = LocalDateTime.parse(dateTimeStrParam, formatter);
System.out.println(" Results after analysis :" + localDateTime);
}

Q/q: quarter , Such as 3; 03; Q3; 3rd quarter.

Best practices

  • Abandoning Date, hug JSR 310

Every time I talk about it 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 , It's the best practice of date time processing .

in addition , About setting time zone during use ( Default time zone ) 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 the default time zone
// Mode one : Common practice
LocalDateTime.now();
// Mode two : Best practices
LocalDateTime.now(ZoneId.systemDefault());

The code is as like as two peas, and the two are the same. . But the second way is best practice .

The reason is that : Doing so can make the code with Clear intent , Eliminate the possibility of ambiguity , Even if you get the default time zone . Take way one , It is where the intention is not clear : In the end, the coder forgot to specify the time zone , Or do you want to use the default 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 default time zone , Please also use the ZoneId.systemDefault() Write it up .

  • Use JVM Be careful with 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 the TimeZone#setDefault() It can be set globally , therefore JVM Any thread of can change the default time zone at will . If the code about time processing Very sensitive to time zones Words , The best practice is that you bind the time zone information to the current session , So that you don't have to be potentially affected by other threads , Robustness is ensured .

explain : The session may only be the current request , It could be one Session, Specifically case make a concrete analysis

summary

adopt Last article Foreshadowing the concept of date and time , With the demonstration of practical operation code in this paper , Get to the bottom of it 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 on 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 , Stay tuned , Progress together .

In this paper, I think about the problem

I don't necessarily understand after reading it , It doesn't have to be understood . Come on , At the end of the article 3 This is a question to help you recover :

  1. Date How do types handle daylight saving time ?
  2. ZoneId and ZoneOffset What's the difference? ?
  3. Usually, if the project encounters the processing of date and time , What are the best practices ?

GMT UTC CST ISO Daylight saving time Time stamp , What kind of ghosts are they ?

Pay attention to me

Share 、 grow up , Refuse to hide and stop . Focus on 【BAT The Utopia of 】 Reply key special column Yes Spring Technology stack 、 Middleware and other small and beautiful pure original Columns . This article has been https://www.yourbatman.cn Included .

This article belongs to the column :JDK Date time , You can get all the content by replying to the column name in the background .

A Brother (YourBatman):Spring Framework/Boot Open source contributor ,Java Architects . Very focused Basic skills training , Believe that the superstructure depends on the foundation , Only a solid foundation can make programmers more energetic . The article is characterized by reconstructing the knowledge system in the form of small and beautiful columns , The whole , Committed to do everyone can understand the best column series . You can add my friends (fsx1056342982) Let's share !

版权声明
本文为[YourBatman]所创,转载请带上原文链接,感谢
https://javamana.com/2021/01/20210121115202587F.html

  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课程百度云