Skip to content

Commit 3a6e5f3

Browse files
committed
Merge pull request giantray#51 from severalfly/master
Why is subtracting these two times (in 1927) giving a strange result?
2 parents a4adac5 + c4ef2b4 commit 3a6e5f3

File tree

1 file changed

+80
-0
lines changed

1 file changed

+80
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
## 为什么相减这两个时间(1927年)会得到奇怪的结果?
2+
3+
### 问题
4+
如果运行下面的代码,我想要做的是解析两个相差1秒的日期字符串:
5+
```java
6+
public static void main(String[] args) throws ParseException {
7+
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
8+
String str3 = "1927-12-31 23:54:07";
9+
String str4 = "1927-12-31 23:54:08";
10+
Date sDt3 = sf.parse(str3);
11+
Date sDt4 = sf.parse(str4);
12+
long ld3 = sDt3.getTime() /1000;
13+
long ld4 = sDt4.getTime() /1000;
14+
System.out.println(ld4-ld3);
15+
}
16+
```
17+
其结果是
18+
```
19+
353
20+
```
21+
为什么`ld4-ld3` 结果不是`1`(因为我期望得到1秒的时间差)而是`353`
22+
23+
如果我把两个日期都换成1秒后:
24+
```java
25+
String str3 = "1927-12-31 23:54:08";
26+
String str4 = "1927-12-31 23:54:09";
27+
```
28+
这样`ld4-ld3`就为`1`
29+
30+
---
31+
java 版本
32+
```
33+
java version "1.6.0_22"
34+
Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
35+
Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)
36+
```
37+
时区(`TimeZone.getDefault()`):
38+
```
39+
sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
40+
offset=28800000,dstSavings=0,
41+
useDaylight=false,
42+
transitions=19,
43+
lastRule=null]
44+
45+
Locale(Locale.getDefault()): zh_CN
46+
```
47+
## 回答
48+
这是12月31号上海时区切换的错误。
49+
50+
[这个页面](http://www.timeanddate.com/time/change/china/shanghai?year=1927)上有关于上海1927的详细说明。因为1927年末尾的午夜,时间回滚了5分52秒,所以"1927-12-31 23:54:08" 实际上发生了两次,并且很明显java解析立即得到了可能的后面一个,而忽略了其差别。
51+
52+
这在经常弄混且丰富的世界时区中还是一个插曲。
53+
54+
如果重新编译[TZDB](https://github.com/nodatime/nodatime/blob/master/src/NodaTime.Demo/StackOverflowExamples.cs#L68)的2013a版本,之前的问题就不再能解释类型行为。在2013a 的版本中,结果将是358秒,切换时间由23:54:03 变为23:54:08。
55+
56+
我能注意到这个都是因为我在[unit tests](https://github.com/nodatime/nodatime/blob/master/src/NodaTime.Demo/StackOverflowExamples.cs#L68)收集像Noda Time 这样的问题
57+
58+
这个测试现在已经被更新,但是也表明没有历史数据是安全的。
59+
60+
在TZDB 2014f中, 这个时间切换移动到了1900-12-31,并且也被修改成唯一的343秒变化(如果你知道我在说啥的话,`t``t+1` 之间是343 秒)。
61+
62+
**更新** 为了回答[ Ken Kin's question](http://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result/6841479#comment22684267_6841479)的问题,看起来像是,对于任何在1900 UTC 之前的时间,java 在他们的标准时间中进行了简单的时区实现。
63+
```java
64+
import java.util.TimeZone;
65+
66+
public class Test {
67+
public static void main(String[] args) throws Exception {
68+
long startOf1900Utc = -2208988800000L;
69+
for (String id : TimeZone.getAvailableIDs()) {
70+
TimeZone zone = TimeZone.getTimeZone(id);
71+
if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {
72+
System.out.println(id);
73+
}
74+
}
75+
}
76+
}
77+
```
78+
上面的代码在我的windows 机器上没有任何输出,所以对于任何相对标准时间在1900年前且有偏移的时间,都会有时间过渡。TZDB 自己有数据回退到更早之前,并且不依赖任何修正过的标准时间(就是`getRawOffset`假设的有效的概念),所以其他库不再需要介绍这个切换。
79+
80+
stackoverflow[链接](http://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result)

0 commit comments

Comments
 (0)