Recently online encountered a more strange problem, check down or very interesting, strange knowledge has increased.
since
One feature of the online service is to determine adulthood from a national id number, by taking the date of birth from the number and then determining whether the person is older than 18. Function is relatively simple, there has been no problem, until yesterday encountered a date resolution exception.
org.joda.time.IllegalInstantException: Cannot parse "19470415": Illegal instant due to time zone offset transition (Asia/Shanghai)
at org.joda.time.format.DateTimeParserBucket.computeMillis(DateTimeParserBucket.java:473)
at org.joda.time.format.DateTimeParserBucket.computeMillis(DateTimeParserBucket.java:411)
at org.joda.time.format.DateTimeFormatter.parseDateTime(DateTimeFormatter.java:928)
......
Copy the code
19470415 is a well-formed string, but joda throws an exception. Here is the code for parsing:
DateTime birthTime = DateTimeFormat.forPattern("yyyyMMdd").parseDateTime(birth);
DateTime adultTime = DateTime.now().plusYears(-18);
return adultTime.compareTo(birthTime) == 1;
Copy the code
Judging from the abnormal information, it may be related to the time zone. After searching on the Internet, joda’s document has indicated how to solve the problem:
Change DateTime to LocalDateTime.
LocalDateTime birthTime = DateTimeFormat.forPattern("yyyyMMdd").parseLocalDateTime(birth);
LocalDateTime adultTime = LocalDateTime.now().plusYears(-18);
return adultTime.compareTo(birthTime) == 1;
Copy the code
After solving the problem, I began to explore the deep reasons behind it.
bearing
I tried to parse the dates one by one from January 1, 1990 to today, and the result was also strange, with only a few days of this exception:
19400601 parse fail, Cannot parse "19400601": Illegal instant due to time zone offset transition (Asia/Shanghai)
19410315 parse fail, Cannot parse "19410315": Illegal instant due to time zone offset transition (Asia/Shanghai)
19420131 parse fail, Cannot parse "19420131": Illegal instant due to time zone offset transition (Asia/Shanghai)
19460515 parse fail, Cannot parse "19460515": Illegal instant due to time zone offset transition (Asia/Shanghai)
19470415 parse fail, Cannot parse "19470415": Illegal instant due to time zone offset transition (Asia/Shanghai)
19480501 parse fail, Cannot parse "19480501": Illegal instant due to time zone offset transition (Asia/Shanghai)
19490501 parse fail, Cannot parse "19490501": Illegal instant due to time zone offset transition (Asia/Shanghai)
Copy the code
What’s so different about these days that makes them so special? Behind all this is the distortion of human nature, or the collapse of morality?
The location where the exception is thrown is in the computeMillis method of the DateTimeParserBucker class in Joda:
.if(iOffset ! =null) {
millis -= iOffset;
} else if(iZone ! =null) {
int offset = iZone.getOffsetFromLocal(millis);
millis -= offset;
if(offset ! = iZone.getOffset(millis)) { String message ="Illegal instant due to time zone offset transition (" + iZone + ') ';
if(text ! =null) {
message = "Cannot parse \"" + text + "\"," + message;
}
throw newIllegalInstantException(message); }}...Copy the code
Millis is a timestamp calculated from the date string, iZone represents the time zone, or if not, the machine-set time zone, in this case Asia/Shanghai. The getOffsetFromLocal method returns an offset that is subtracted from the local time to get the UTC time. The getOffset method also returns an offset, which is added to the UTC time to get a local time. Joda calls getOffsetFromLocal to calculate an offset from the local time millis. Call getOffset to calculate an offset from the UTC time. Normally, these two offsets should be consistent, and if they are inconsistent, an exception will be thrown.
In the example 19470415, getOffsetFromLocal evaluates to 28800000 milliseconds, or 8 hours; GetOffset calculated 32.4 million milliseconds, or nine hours. And where did that hour come from?
turn
Take a look at the comment for the getOffset method:
The offset returned by getOffset may differ due to daylight saving time or policy reasons!
Moving on to the joda code, org.joda.time.tz.src contains a set of time zone specific code, which is the time zone data content from IANA. Iana Time Zone Database can be downloaded here.
We find the time zone data, code address of Asia in Joda. Using Shanghai as the keyword, the following set of data was found:
This group of dates looks a little familiar, isn’t it the same group of dates before the date resolution anomaly?
The time zones of Asia/Shanghai may differ from UTC at certain times in history due to daylight saving time, wars, etc. For example, in 1919 tianjin briefly implemented daylight saving time, which gave the people a lot of trouble, and then changed it back.
How do I read iana’s time zone data? Detailed rules can be found here. The D in the last column stands for CDT, daylight saving time; S stands for CST, or standard time. To make a rough guess at the reading of this data, take the example of the exception triggered by our service on April 15, 1947, at 00:00 on April 15, daylight saving time is adopted, and the time is adjusted to 1:00. This gives you an extra hour of UTC time.
us
Finally, we know where that extra hour came from. Knowing the truth, I really want to curse.
Aside: Daylight saving time is a great invention, if it is to save energy, obviously modify the work schedule can be solved, change to make a lot of things are confused.