Original: Coding diary (wechat official ID: Codelogs), welcome to share, reprint please reserve the source.

Introduction to the

GMT+8 = GMT+8 = GMT+8 = GMT+8 = GMT+8

$ TZ='GMT-8' date -d@1647658144 +'%F %T %:z'The 2022-03-19 10:49:04 + 08:00If GMT+8 is used, it will be 16 hours slower
$ TZ='GMT+8' date -d@1647658144 +'%F %T %:z'The 2022-03-18 18:49:04-08:00Copy the code

In Java, it looks like this:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
String dateStr = dtf.format(Instant.ofEpochSecond(1647658144).atZone(ZoneId.of("GMT+8")));
System.out.println(dateStr);
// Output 2022-03-19 10:49:04 +08:00
Copy the code

This makes people a little confused, after a period of time search, found in the time zone expression form there are many knowledge points!

Offset representation of a time zone

As we all know, in order to facilitate the conversion of local time between regions, people divide the world into 24 time zones, with Greenwich Observatory (GMT) as the zero time zone, and 12 time zones in the east and west directions respectively, so there is a natural time zone expression with GMT as the prefix, as follows:

GMT+8 means East 8, which is used in China, and GMT-8 means West 8. If the local time at Greenwich Observatory is 0 o ‘clock on 2022-03-19, the local time at GMT+8 is 8 o ‘clock on 2022-03-19, and the local time at GMT-8 is 8 hours ahead. That’s 16:00 on 2022-03-18.

Note that the local time in each region is expressed differently, but it is actually the same time (absolute time). Understand the difference between local time and absolute time.

GMT+8 is the time zone notation supported in Java, so why GMT-8 in Linux? In Linux, gmT-8 can also be written as /etc/GMT-8, which is the standard name:

$ TZ='Etc/GMT-8' date -d@1647658144 -Is
2022-03-19T10:49:04+08:00
Copy the code
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss XXX");
String dateStr = dtf.format(Instant.ofEpochSecond(1647658144).atZone(ZoneId.of("Etc/GMT-8")));
System.out.println(dateStr);
// Output 2022-03-19 10:49:04 +08:00
Copy the code

/etc/GMT-8 is a time zone representation similar to GMT+8, but with the +- sign reversed.

Ok, although the above differences are clarified, but the time zone representation is not complete, continue to read…

In addition to the GMT+8 representation, we often see the UTC+8 representation, which is the UTC time zone representation.

Immediate GMT or UTC? This is because GMT is based on Greenwich Observatory, but the earth is not a perfect sphere and the rotation speed is slowing down, so the earth rotation speed is not uniform, which leads to the Greenwich Observatory as the time baseline is not accurate.

To get a better measure of time, scientists invented UTC, which measures time more accurately than GMT by the number of caesium atom transitions. GMT is adjusted to align with UTC every few years to keep GMT accurate.

So now that you have a more accurate UTC, you have a time zone representation prefixed with UTC, such as UTC+8 for Chinese time zones.

The list of offset expressions for each time zone is as follows:

Offset notation describe
GMT+8 8 hours more than GMT
Etc/GMT-8 With the GMT + 8,+-No. On the contrary
UTC+8 With the GMT + 8
GMT+08:00 Accurate to the minute
GMT+08:00:00 Accurate to the second
GMT+0800 Accurate to the minute level, omit the colon
GMT+080000 Accurate to the second level, omit the colon
+ 08:00 Down to the minute level, omit prefixes
+ 08:00:00 Accurate to the second level, omit the prefix
+ 0800 To minute accuracy, omit prefixes and colons
+ 080000 Down to the second level, omit prefixes and colons
Z It is the same as GMT, UTC, GMT+0, and UTC+0

A regional representation of a time zone

In addition to using offsets to represent time zones, people also define time zones by region/city for convenience. For example, Asia/Shanghai and Asia/Hong_Kong both represent east 8. You can check the time zone database for specific city names.

In addition, in order to simplify the regional Time zone expression, a set of Time zone abbreviations are defined. For example, CST is the abbreviation of China Standard Time. You can view the definition of various abbreviations in the Time zone abbreviations.

Note that time zone abbreviations are generally not recommended because they are often named repeatedly, For example, CST is Central Standard Time(UTC-6), China Standard Time(UTC +8), Cuba Standard Time(UTC-5).

Because the interpretation of CST by different software may be different, there will be a time difference of 13 or 14 hours, which often occurs when Java is combined with MySQL. I also wrote a special article on MySQL timestamp has a time zone problem? For scenarios where time zone abbreviations are mandatory, use the Hong Kong time zone abbreviation HKT, which is not duplicated and is in the same time zone as Shanghai.

Region notation describe
Asia/Shanghai Shanghai time zone, namely east 8 zone
CST Use time zone abbreviations with caution

Time zone in Java

In Java, TimeZone related classes are TimeZone and ZoneId. TimeZone is the old TimeZone class, while ZoneId is the new TimeZone class. It has two subclasses, ZoneOffset and ZoneRegion, representing offset and zone representation respectively.

Which time zones do they support? To verify this, write a Demo as follows:

public static void main(String[] args) {
	printZoneId("+ 08:00." ");
	printZoneId("+ 0800");
	printZoneId("GMT+8");
	printZoneId("Etc/GMT-8");
	printZoneId("UTC+8");
	printZoneId("Asia/Shanghai");
	printZoneId("CST");
	printZoneId("Z");
}

public static void printZoneId(String zone){
	ZoneId zoneId;
	if(! ZoneId.SHORT_IDS.containsKey(zone)){ zoneId = ZoneId.of(zone); }else{
		zoneId = ZoneId.of(ZoneId.SHORT_IDS.get(zone));
	}
	TimeZone timeZone = TimeZone.getTimeZone(zone);
	ZoneOffset zoneOffset = zoneId.getRules().getOffset(Instant.now());
	DateTimeFormatter dtf = DateTimeFormatter.ofPattern("xxx ZZZ O OOOO");
	System.out.printf("%-14s -> %-28s -> class:%s -> TimeZone.offset:%d \n", zone, dtf.format(zoneOffset),
			zoneId.getClass().getSimpleName(), timeZone.getRawOffset());
}
Copy the code

The output is as follows:

+08:00 -> +08:00 +0800 GMT+8 GMT+08:00 -> class:ZoneOffset -> TimeZone.offset:0 +0800 -> +08:00 +0800 GMT+8 GMT+08:00 ->  class:ZoneOffset -> TimeZone.offset:0 GMT+8 -> +08:00 +0800 GMT+8 GMT+08:00 -> class:ZoneRegion -> TimeZone.offset:28800000 Etc/GMT-8 -> +08:00 +0800 GMT+8 GMT+08:00 -> class:ZoneRegion -> TimeZone.offset:28800000 UTC+8  -> +08:00 +0800 GMT+8 GMT+08:00 -> class:ZoneRegion -> TimeZone.offset:0 Asia/Shanghai -> +08:00 +0800 GMT+8 GMT+08:00 -> class:ZoneRegion -> TimeZone.offset:28800000 CST -> -05:00 -0500 GMT-5 GMT-05:00 -> class:ZoneRegion -> TimeZone.offset:-21600000 Z -> +00:00 +0000 GMT GMT -> class:ZoneOffset -> TimeZone.offset:0Copy the code
The time zone of writing ZoneId TimeZone
+ 08:00 support Does not support
+ 0800 support Does not support
GMT+8 support support
Etc/GMT-8 support support
UTC+8 support Does not support
Asia/Shanghai support support
CST Supported, it stands for Western North American time, not China standard time Supported, it stands for Western North American time, not China standard time
Z support support

Offset notation is different from region notation

Although both offset and zone representations can represent time zones, they are not completely equivalent due to daylight saving time.

Daylight Saving Time (DST), also known as Daylight Saving Time (DST), is a Time set one hour ahead of Time in summer to make full use of Daylight resources and save electricity.

China in 1986 to 1991 also implemented daylight saving time, in 1986 to 1991 each year from the middle of April on the first Sunday at 2 o ‘clock (Beijing time), the clock forward one hour, that is, the hands from 2 to 3, daylight saving time began; By 2am on the first Sunday in mid-September (Beijing Daylight Saving Time), the clocks will be put back one hour, that is, the hands will be moved from 2am to 1am, the daylight saving time will end. From 1986 to 1991, except 1986, the first year of daylight saving time, from May 4 to September 14, the other years are in accordance with the provisions of the period of time.

Therefore, there will be the following phenomenon that looks a little strange:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
Instant instant = Instant.ofEpochSecond(515527200);
System.out.println(dtf.format(instant.atZone(ZoneId.of("Asia/Shanghai"))));
// Output 1986-05-04 03:00:00 Asia/Shanghai
System.out.println(dtf.format(instant.atZone(ZoneId.of("GMT+8"))));
1986-05-04 02:00:00 GMT+08:00 is displayed
Copy the code

Why is Asia/Shanghai output 3 o ‘clock and GMT+8 output 2 o ‘clock? The reason is that 1986-05-04 02:00:00 is when China began to implement daylight saving time, and clocks were moved forward one hour.

Why does GMT+8 output 2? The time zones of China, Malaysia, the Philippines, and Singapore are all GMT+8. Only China is in DAYLIGHT saving time (DST), and no region information is sensed in GMT+8, so Java has to calculate local time without DST.

Strange phenomena caused by daylight saving time

It is the existence of daylight saving time that leads to the application may have strange phenomena and even bugs, as follows:

  1. The date command failed because daylight saving time changes from 2 o ‘clock to 3 o ‘clock
$ TZ='Asia/Shanghai'Date -d 1986-05-04T02:00:00 +% S date: invalid date '1986-05-04T02:00:00' $TZ='Asia/Shanghai' date -d 1986-05-04T03:00:00 +%s
515527200
Copy the code
  1. Format the output after parsing the time, and find that the output is different
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
ZonedDateTime time1 = ZonedDateTime.parse("1986-05-04 02:00:00 Asia/Shanghai", dtf);
System.out.println(time1.format(dtf));
// Output 1986-05-04 03:00:00 Asia/Shanghai
Copy the code
  1. Add 1 hour and find 2 hours or no change at all
public static void main(String[] args) {
	DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
	// Add 1 hour to start daylight saving time
	ZonedDateTime time1 = ZonedDateTime.parse("1986-05-04 01:00:00 Asia/Shanghai", dtf);
	printZonedDateTime(time1);
	printZonedDateTime(time1.plusHours(1));
	
	// Add 1 hour to end daylight saving time
	ZonedDateTime time2 = ZonedDateTime.parse("1986-09-14 01:00:00 Asia/Shanghai", dtf);
	printZonedDateTime(time2);   			
	printZonedDateTime(time2.plusHours(1));   
}

private static void printZonedDateTime(ZonedDateTime time){
	DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss VV");
	System.out.println(time.format(dtf));
}
Copy the code

The output is as follows:

1986-05-04 01:00:00 Asia/Shanghai 1986-05-04 03:00:00 Asia/Shanghai // 1986-09-14 01:00:00 Asia/Shanghai 1986-09-14 01:00:00 Asia/Shanghai //Copy the code

Why is that? The reason is that while the local time appears unchanged, the time zone represented by Asia/Shanghai has changed.

Yyyy-mm-dd HH: MM :ss VV = yyyY-MM-DD HH: MM :ss VV XXX = YYYY-MM-DD HH: MM :ss VV XXX = YYYY-MM-DD HH: MM :ss VV XXX

1986-05-04 01:00:00 Asia/Shanghai +08:00
1986-05-04 03:00:00 Asia/Shanghai +09:00
1986-09-14 01:00:00 Asia/Shanghai +09:00
1986-09-14 01:00:00 Asia/Shanghai +08:00
Copy the code

In Java, to convert ZoneRegion to ZoneOffset, you need to pass an instant time parameter as follows:

/ / output + 08:00
Instant instant = Instant.now();
System.out.println(ZoneId.of("Asia/Shanghai").getRules().getOffset(instant));
// Output +09:00, 1986-05-04 02:00:00 +08:00 is in daylight saving time, an increase of 1 hour
Instant instant = Instant.ofEpochSecond(515527200);
System.out.println(ZoneId.of("Asia/Shanghai").getRules().getOffset(instant));
Copy the code

Daylight saving time is such a self-deceiving practice that China hasn’t practiced it since 1991!

Content of the past

Common Socket network exception scenario analysis Mysterious Backlog parameters and TCP connection queue Linux command pick-ups – Getting started Character encoding puzzle